Introduction

This tutorial is divided in 3 parts. We will build an Ionic 3 example app with a question and answer format (Q&A), where users will be able to ask and answer questions. The home page will have a list of categories. Each category will have a list of questions, and each question will have a list of answers. Users will also have the possibility to vote the questions and answers (up-vote, down-vote), plus a form for creating questions and answers, similar to StackOverflow.


Part 1 will explain how to create the core of the app in a local environment. Part 2 will show how to add a backend and Database to your Ionic 2+ app. Part 3 is about deploying all these components into a production environment.
We will be releasing Part 2 and 3 in the upcoming weeks.


In our previous tutorials we discussed about Ionic Framework introduction and key components and also how to Setup your development environment to build Ionic apps. We also learned how should an Ionic App Architecture look like. If you are new to ionic framework you should consider reading these posts before.


This tutorial takes you through the steps of creating an Ionic application in TypeScript. It guides you through every step from setup to a complete featured case, which illustrates the fundamental attributes of an ionic app. Data binding, a sensible project structure, navigation, services, dependency injection and remote data access, among others.


We will learn enough core Angular and Ionic to get started and gain confidence that Ionic can do whatever we need it to do. We will be covering a lot of ground at an introductory level, but we will find plenty of references to topics with greater depth.


If you click "GET THE CODE" buttom from above, you will get the code of the full example app, not just from Part 1, so there will be code not explained in this part. Part 1 just explains how to get data from a local json, however, in Part 2 we will explain how to pull data from a remote DB. The categories are stored in a local json, but questions and answers are stored in the remote DB and accessed through an API (explained in Part 2).

What are we going to build?

This ionic app consists in a CRUD (Create, Read, Update, Delete) of Questions and Answers where users can post new questions and answer others.


It will have the following functionalities:

  • Manage Questions (Create, Update, Delete)
  • Manage Answers (Create, Update, Delete)
  • List all the Questions in a feed format
  • List all the Answers of a particular Question
  • Enable people to vote Questions and Answers (up-votes and down-votes)

This is how the final app will look like:


In this first part, you will learn how to:

  • Initialize your application using Ionic CLI
  • Create classes to represent the objects from the model
  • Create services to access and handle data
  • Create pages and components to represent the functionalities and display the user interface

Project structure

After following the setup instructions for creating a new project, let’s walk through the anatomy of this particular Ionic app.


Ionic’s app typical architecture includes:

  • Modules: They help organize an application into cohesive blocks of functionality by wrapping components, pipes, directives, and services.
  • Components: They are the most basic building block of an UI, and the main way we build and specify elements and logic on the page.
  • Templates: They are used to define a component view. A template looks like regular HTML, with typical HTML element tags, but it also has some differences.
  • Services: Almost anything can be a service, any value, function, or feature that your application needs. A service is typically a class with a narrow, well-defined purpose.
  • External resources: Databases, API’s, etc, are fundamental as they will enable our app to interact with the outside world.

Read about the anatomy of an Ionic App to learn more about each of these core building blocks.


Now, let’s go deeper and map the project structure to the app’s architecture, so we can fully comprehend how all the pieces interact with each other.


Inside the src directory we find our raw, uncompiled code. This is where most of the work for an Ionic 2+ app will take place. When we run ionic serve, our code inside src/ is transpiled into the correct Javascript version that the browser understands (currently, ES5). That means we can work at a higher level using TypeScript, but compile down to the older form of Javascript the browser needs.


Let’s go through each of the app’s file and see what do we have inside.

App folder

app.component.ts

It defines the basic structure and initial navigation of the app. In our case we have a side menu navigation. In this file, we define which page would be the first one and the options and navigations of the side menu. Here, we will also get notified when the platform is ready and our plugins (cordova, native stuff) are available. That enables you to do any higher level native things you might need.


app.html

Here we define the navigation and it’s root. In this template, we set up an ion-menu to function as a side menu, and then an ion-nav component to act as the main content area.


app.module.ts

This file is the entry point for our app. It includes the main Angular 4 module (NgModule) of our app. It is also the place where we should declare the vast majority of our dependencies (such as pages, custom components, services, etc) and ‘teach’ the main module how to use them.


app.scss

This is the main entry point for our app Sass files/styles. Here is the place you should include your app shared imports and global Sass you may use and apply globally. Additionally, this file can be also used as an entry point to import other Sass files to be included in the output css. This is NOT the place to include shared Sass variables. You have to define, adjust, add those in theme/variables.scss.


main.ts

This is an ionic auto-generated file and it takes care of the bootstrapping of the app.

Pages folder

Each page has its own folder. Within that folder you will find every related file for that page. This includes the html for the layout, Sass for the styles and the main page component.


Let’s have a closer look at what I’m talking about deglossing the feed page.


learn-feed.html

All the layout for the page. Everything we do is crafted using cutting edge techniques and technologies. We always code towards customizability and ease of use. We also make use of the awesome ionic components.


learn-feed.ts

Here are all the functionality and interactions of the page and where the view logic should go.


learn-feed.scss

Centralized styles for this page. This app structure makes it easy for you to know and centralize in one place where you should change stuff.

Theme folder

Here you will find all the variables, mixins, shared styles, etc, that will make your app customizable and extendable.

Maybe you don’t know Sass? Briefly, it is a superset of css that will ease and speed your development cycles incredibly.


common

Under the theme/common folder you will find (classified by component/functionality) all the shared styles, this way we encourage code reuse and prevent DRY.


variables.scss

This is the predefined ionic file where you should include all the variables you may use in your app. For example, all the colors used within the app. Having those in variables, will enable you to play around and try different color schemes easily.

Services folder

This folder is for all the services you will use to access the data that will be presented in the app. In our case, we have two different kind of services. The ones that interact with the remote backend API (question and answer) and the one that interacts with the local data json file (categories).

In this first part we will only focus on the local data json files.


learn.model.ts

Angular 4 relies heavily on typescript and object oriented programming. It is a good and recommended approach to follow these principles along the way. That is why we create models (typical typescript classes with object representations) to represent the data that’s going to be presented in the layout. That is what you will find in this file.


learn.service.ts

In this file you will find methods to access and pull the data that will be presented in the learn pages. In our case we are using sample data pulled from a json file.


question.service.ts - answer.service.ts

In these files we will be handling the communication and interaction with our backend API. We won’t cover these on this tutorial. We will address this in Part 2.

Assets folder

All the images you may use in your app as well as other assets, go here. In our case we simplified the data layer of some parts of the app by creating a json file with sample data.

App’s navigation

Before we start thinking about navigation, we must consider the type and amount of data you want to display in your app. Don't forget you will use navigation to show and structure your data, that is why it should follow the information structure of your app and not the other way round.

It is important to keep the best practices for navigation design. This ensures that people will be able to use and find the most valuable features in your app.


You can find more information about the details of UI/UX of navigation in Essential Mobile Components - Navigation.


A little more about the navigation

Navigation in Ionic 2+ apps works like a simple stack, where we push new pages onto the top of the stack. This moves us forward in the app and shows a back button. To go backwards, we pop the top page off. Since we set this.navCtrl in the constructor, we can call this.navCtrl.push(), and pass it the page we want to navigate to. We can also pass it an object containing data we would like to pass to the page being navigated to. Using push to navigate to a new page is simple, but Ionic’s navigation system is very flexible. Check out the navigation docs to see more advanced navigation examples.


For example, this is how we handle navigation for the side menu component. We are not pushing pages the normal way. Instead, we set them as root pages clearing previous navigation stacks as that is the user experience we want to achieve.


app.component.ts

openPage(page) {
	// close the menu when clicking a link from the menu
	this.menu.close();
	// navigate to the new page if it is not the current page
	this.nav.setRoot(page.component, page.params);
}

app.html

<ion-menu [content]="content" [swipeEnabled]="false">
	<ion-content class="menu-content">
		<ion-list class="menu-list">
  		<button ion-item detail-none *ngFor="let page of pages" (click)="openPage(page)">
    		{{ page.title }}
  		</button>
		</ion-list>
	</ion-content>
</ion-menu>

The “internal” navigation of the app, on the other hand, is handled by pushing pages like this:


learn-feed.ts

openDetails(params) {
  this.navCtrl.push(LearnDetailsPage, params);
}

UI/UX

Ionic apps are made of high-level building blocks called components, which allow you to quickly construct an interface for your app. These include modals, popups and cards. They are reusable UI elements that serve as the building blocks for your mobile app, made up of HTML, CSS, and sometimes JavaScript. Every Ionic component adapts to the platform on which your app is running. This is called Platform Continuity and you can find more information in the Theming section of the Ionic Framework documentation.


In this example app, we have different layouts. For each view we need different UI components. Here’s a short list with the most important components we used for each view and a link to the specifics of the implementation of that view.


  • Learn feed view
    • A feed showing the different Ionic concepts you need to learn.
    • Components:
      • Ionic content cards

  • Learn details view
    • A view to show the details of a particular concept. These details include a short explanation of the concept and a list of questions about this concept.
    • Components:
      • Ionic content cards

  • Question details view
    • A view to show the list of answers to a particular question.
    • Components:
      • Ionic content cards

  • Manage question view
    • A view to enable the creation and modification of a question.
    • Components:
      • Ionic modal
      • Ionic form inputs

  • Manage answer view
    • A view to enable the creation and modification of an answer.
    • Components:
      • Ionic modal
      • Ionic form inputs

In this example app we used some handy Ionic UI components like: Side menus, Content Cards, Modals and Form inputs.

Please feel free to dig the library of UI components that Ionic has in their components documentation page.

Data Integration

The key to an evolving app is to create reusable services to manage all the data requests to your backend.

As you may know, there are many ways when it comes to data handling and backend implementations. In this tutorial we will explain how to consume data from a static json file with dummy data. In Part 2 we will show you how to build and consume data from a backend API with Strongloop (a node.js framework perfectly suited for REST API’s) and MongoDB (to store the data).


Both implementations (static json and remote backend API) need to worry about handling data requests. This works the same and it’s independent on the way you implement the backend. We will talk about models and services and how they work together to achieve this.


We encourage the usage of models in combination with services for handling data all the way from the backend to the presentation flow.

Models

Domain models are important for defining and enforcing business logic in applications and are especially relevant as apps become larger and more people work on them.

At the same time, it is important that we keep our applications DRY and maintainable by moving logic out of components themselves and into separate classes (models) that can be called upon. A modular approach such as this, makes our app's business logic reusable.


To learn more about this, please visit this great post about angular 2 domain models.

Services

Ionic 2+ is implemented on top of Angular 4 and it borrows it’s best parts. Angular 4 enables you to create multiple reusable data services and inject them in the components that need them.

Refactoring data access to a separate service, keeps the component lean and focused on supporting the view. It also makes it easier to unit test the component with a mock service.

To learn more about angular services, please visit Angular documentation about services.


In our case, we defined a model for the learn view data we are pulling from the static json file. This model is used by the learn.service.ts.


learn.model.ts

	export class CategoryModel {
		slug: string;
		title: string;
		description: string;
		background: string;
		tags: Array<string>;
	}

learn.service.ts

import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import { Http } from '@angular/http';

@Injectable()
export class LearnService {
  constructor(public http: Http){}

  getFeedCategories(){
    return this.http.get("./assets/categories/categories.json")
      .map((res:any) => res.json());
  }
}

And we use this service in the learn-feed.ts view to load the Learn Feed categories.


learn-feed.ts

ionViewWillEnter() {
	this.learnService.getFeedCategories()
	.subscribe(data => {
		this.categories = data.categories
	});
}
		

Each time we add a new service remember that the Angular injector does not know how to create that Service by default. If we ran our code now, Angular would fail with an error.

After creating services, we have to teach the Angular injector how to make that Service by registering a Service provider.


According to the Angular documentation page for dependency injection there are two ways to register the Service provider:

  • In the Component itself
    @Component({
    	selector: 'my-heroes',
    	providers: [HeroService],
    	template: `<h2>Heroes</h2><hero-list></hero-list>`
    })
  • In the Module (NgModule)

In our case, we register all services in the app.module.ts


app.module.ts

@NgModule({
  declarations: [
    MyApp,
    LearnFeedPage,
    ...
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    SDKBrowserModule.forRoot()
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    LearnFeedPage,
    ...
  ],
  providers: [
    LearnService,
...,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})

Dependency Injection

One side note on the importance of Dependency Injection from the software architecture principles point:

Remember we just mentioned that we “inject” data services in the components that need them? Well, this concept is called Dependency Injection and it is super important to know more about this.


Do we new() the Services? No way! That's a bad idea for several reasons including:

  • Our component has to know how to create the Service. If we ever change the Service constructor, we will have to find every place we create the service and fix it. Running around patching code is error prone and adds to the test burden.
  • We create a new service each time we use new(). What if the service should cache results and share that cache with others? We couldn't do that.
  • We are locking the Component (where we new() the service) into a specific implementation of the Service. It will be hard to switch implementations for different scenarios. Can we operate offline? Will we need different mocked versions under test? Not easy.

We get it. Really we do. But it is so ridiculously easy to avoid these problems that there is no excuse for doing it wrong.

Final thoughts

In this tutorial you learned how to create the main components of an Ionic 2+ mobile app. We also discussed about key concepts an ionic app such as project structure, navigation and data integration.


If you click "GET THE CODE" buttom from above, you will get the code of the full example app, not just from Part 1. If you have questions please leave a comment below.


Part 2 will show how to add a Loopback backend and a Mongo DB to our Q&A app and Part 3 is about deploying all these components into a production environment. We will release them in the upcoming weeks.

You can also learn by example using our ionic templates.