Mastering Ionic 2 The Definitive Guide - huang-qing/ionic3-platform GitHub Wiki

Mastering Ionic 2 The Definitive Guide

Confguring your environment

  • Apache Cordova (version 5+)
  • Node JS (version 5+)
  • NPM (Node Package Manager - version 3+)
  • Xcode (for iOS app development)
  • Android SDK (for Android development)

Visual Studio 2015

Microsoft’s Visual Studio 2015 provides a range of cross platform development tools specifcally for developers looking to create, amongst others, iOS apps.

Visual Studio 2015 can be downloaded here: https://www.visualstudio.com/en-us/features/mobile-app-development-vs.aspxd

Installing the Ionic SDK

npm install -g ionic cordova
npm install -g ionic cordova

Beginning Ionic 2 Development

mkdir apps
chmod -R 775 apps
cd apps
ionic start myApp blank --v2

the Ionic CLI has:

  • Created a blank project
  • Installed NPM packages
  • Added initial native plugins (more on these later)
  • Added the iOS platform by default (only mobile platform to be installed)
  • Provided us with hints about what we might want to do next

Instead of a blank project we could have chosen any of the following instead:

// Create a project with the sidemenu template
ionic start myApp sidemenu --v2

//Create a project with the tabs template
ionic start myApp tabs --v2

//Create a project with the tutorial template
ionic start myApp tutorial --v2

We instructed the CLI to build for Ionic 2 (using the --v2 flag).

some of the Ionic CLI commands that you’ll most likely use for development:

Note: cd into the root directory of your Ionic 2 app before running the following commands

// Add Android platform
ionic platform add android

// Remove Android platform
ionic platform rm android

// Remove iOS platform
ionic platform rm ios

// Run your Ionic app in the web browser
ionic serve

// Display Ionic app in the web browser as separate iOS / Android / Windows
// Phone views by adding a lowercase L as a flag
ionic serve -l

// Run your app on a connected iOS device
ionic run ios

// Run your app on a connected Android device
ionic run android

// Prepare & compile your app for iOS
ionic build ios

// Prepare & compile your app for Android
ionic build Android

// Print details about your system environment
ionic info

// Install plugins
ionic plugin add <name-of-plugin-here>

// Remove installed plugin
ionic plugin remove <name-of-plugin-here>

// List all installed plugins
ionic plugin ls

// Add a page to your Ionic app
ionic g page name-of-page-here

// Add a service to your Ionic app
ionic g provider name-of-service-here

// Add a pipe to your Ionic app
ionic g pipe name-of-pipe-here

// Add a directive to your Ionic app
ionic g directive name-of-directive-here

// We’ll explore adding pages, services, directives & pipes in following chapters
// so don’t worry if these make no sense to you at the moment!

Making sure you are at the root directory of your newly created app run the following command in the Terminal:

ionic serve

The tasks that are run by this command consist of:

  • Cleaning the contents of the www directory

  • Linting TypeScript files for the app then transpiling and concatenating those into a single JavaScript file

  • Compiling Sass to CSS and concatenating all of the app stylesheets into a single CSS file

  • Copying the newly generated JavaScript and CSS fles to the re-created www/ build directory

  • Copying custom assets, such as images, from the src/assets directory to the www/assets directory

  • Listening for changes to the Sass/TypeScript/HTML fles used within the app, re-running these tasks and reloading the app within the browser to display these changes

we can actually preview our app is if it were running on the following 3 platforms simultaneously:

  • iOS
  • Android
  • Windows Phone

And we accomplish this using the following (slightly modifed) command:

// Add the letter L (in lowercase) as a flag after the ionic serve command
ionic serve -l

The architecture of an Ionic 2 app


Decorators & Classes

This fle should look like the following:

import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';

@Component({
    selector: 'page-home',
    templateUrl: 'home.html'
})

export class HomePage {
    constructor(public navCtrl: NavController) {}
}

There are 3 main elements to this fle:

  • Modules

    At the top of the page a couple of import statements were automatically added when we created our app using the Ionic CLI tool.

  • Decorator

    • @Component
    • @Directive
    • @Pipe
    • @Injectable
  • Class

    • Imported modules

    • Class decorator

      The @Component decorator

    • Class declaration

      export class EquipmentItemsPage
      {
      // Class contents displayed in here
      }
    • Constructor

      constructor(public nav : NavController,public np : NavParams){
      
      }

Creating new components

ionic g page about

The following amendments to the myApp/src/app/app.module.ts file demonstrate how a new component must be registered (highlighted in bold):

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
//1-import
import { AboutPage } from '../pages/about/about';

@NgModule({
declarations: [
    MyApp,
    HomePage,
    //2-declare
    AboutPage
],
imports: [
    IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
    MyApp,
    HomePage,
    //3-declare
    AboutPage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}

You MUST import and declare all page components used within your app (whether they are imported into other page components or not) inside of the app.module.ts fle otherwise the compiler will complain when trying to publish your app.


Ionic 2 Navigation

App navigation in Ionic 2 centres around the concept of a navigation stack:

  • To navigate to a page you push that page onto the top of the stack

  • To go back you pop that page off the stack

Customising the transition

The NavController class provides the following methods which allow developers to control how the current transition behaves:

  • animate (Whether or not the transition should animate - accepts a boolean value)

  • animation (The type of animation the transition should use - currently any of the following strings: md-transition [android animation], ios-transition [iOS animation] and wp-transition [Windows Phone animation])

  • direction (The direction in which the user is navigating - accepts a string value of forward or back)

  • duration (The length in milliseconds that the animation will take to complete)

  • easing (The type of easing for the animation to use)

export class HomePage {
    public params : any;
    constructor(public navCtrl: NavController) {
    ...
    }

    setNavigationLink(){
        let opts = { animate: true, animation: "wp-transition", duration: 2500}
        this.navCtrl.push(AboutPage, this.params, opts);
    }
}

Lifecycle events

We can also control what happens within our app before, during and after pages have loaded with the following navigation life cycle events:

  • ionViewDidLoad (triggered only once per page after the page has completed loading and is now the active page)

  • ionViewWillEnter (run when the requested page is about to enter and become the active page)

  • ionViewDidEnter (run when the page has completed entering and is now the active page)

  • ionViewWillLeave (run when the page is about to leave and no longer be the active page)

  • ionViewDidLeave (run when the previously active page has completed leaving)

  • ionViewWillUnload (run when the page is about to be destroyed and all of its elements removed)

  • ionViewCanEnter (runs before the page view can enter)

  • ionViewCanLeave (runs before the page view can leave)

Setting the root page

In Ionic 2 the root page is the frst page to be loaded by the app and is defned in the src/app/app.component.ts fle with the following code

import { HomePage } from '../pages/home/home';

@Component({
    template: `<ion-nav [root]="rootPage"></ion-nav>`
})

export class MyApp {
rootPage = HomePage;
this.nav.setRoot(whateverPageYouWantToBeTheRootPage);

Tabs template

If you open the src/pages/tabs/tabs.html fle of a newly created Ionic 2 app that uses the tabs template you’ll see the following markup:

<ion-tabs>
    <ion-tab [root]="tab1Root" tabTitle="Home" tabIcon="home"></ion-tab>
    <ion-tab [root]="tab2Root" tabTitle="About" tabIcon="information-circle"></ion-tab>
    <ion-tab [root]="tab3Root" tabTitle="Contact" tabIcon="contacts"></ion-tab>
</ion-tabs>

The multiple root pages references displayed here are defned in the tabs.ts file (that is contained within the same directory as the tabs.html fle):

import { Component } from '@angular/core';
import { HomePage } from '../home/home';
import { AboutPage } from '../about/about';
import { ContactPage } from '../contact/contact';

@Component({
    templateUrl: 'tabs.html'
})
export class TabsPage {
    // this tells the tabs component which Pages
    // should be each tab’s root Page
    tab1Root: any = HomePage;
    tab2Root: any = AboutPage;
    tab3Root: any = ContactPage;

    constructor() {
    }
}

Side Menu template

If you create a new Ionic 2 app using the sidemenu template and open the src/app/app.html file you’ll see the following markup:

<ion-menu [content]="content">
    <ion-header>
        <ion-toolbar>
            <ion-title>Menu</ion-title>
        </ion-toolbar>
    </ion-header>

    <ion-content>
        <ion-list>
            <button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
            {{p.title}}
            </button>
        </ion-list>
    </ion-content>
</ion-menu>
<!-- Disable swipe-to-go-back because it’s poor UX to combine STGB with side
menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>

There are a few things to pay attention to here:

  • The <ion-menu> element is used to create the side menu

  • This has a [content] property with a value of content

  • The content value for this property is a reference to the local variable set on the <ion-nav> element as #content

  • The navigation items for the side menu are injected as buttons through the use of an ngFor loop (we’ll cover these in the next section) which pulls values from a pages object

  • Each button injected into the menu by the ngFor loop has a click event which calls an openPage function that is passed the page object from the loop

take a look at the src/app/app.component.ts file

@Component({
    templateUrl: 'app.html'
})

export class MyApp {
    @ViewChild(Nav) nav: Nav;
    rootPage: any = Page1;
    pages: Array<{title: string, component: any}>;

    constructor(public platform: Platform) {

    // used for an example of ngFor and navigation
    this.pages = [
        { title: 'Page One', component: Page1 },
        { title: 'Page Two', component: Page2 }
        ];
    }

    initializeApp() {

    }

    openPage(page) {
    // Reset the content nav to have just this page
    // we wouldn’t want the back button to show in this scenario
    this.nav.setRoot(page.component);
    }
}
  • Our class imports and uses the Angular 2 ViewChild component (which allows access to a different component class and its methods) to allow the side menu template to be able to implement the methods of the NavController object

  • The menu options are defned as an array called pages, which is subsequently initialised within the class constructor (this is then able to be iterated through and used to create navigation buttons for the <ion-menu> element in the src/app/app.html template using the ngFor directive)

  • The openPage function uses the setRoot method of the NavControlle class to avoid usability issues with the back button being displayed when a side menu navigation option is selected


Templates

IMPORTANT - DON’T forget, when creating new components to be used within your app, to import these into the src/app/app.module.ts fle and then add their class names to the following areas of the @NgModule confguration:

  • declarations

  • entryComponents

Event binding

<ion-item *ngFor="let page of pages" (click)="setNavigationLink(page)">

For further information on the topic visit the following Angular 2 documentation: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#event-binding

Angular 2 template directives

https://angular.io/docs/ts/latest/guide/template-syntax.html#!#star-template

ngFor

The ngFor directive is prefxed with an asterisk like so:

<div *ngFor="let page of pages">

An embedded template for the above would look like the following:

<template [ngFor]="let page of pages">
// Render each template content here
</template>

ngSwitch

<span [ngSwitch]="technology">
    <span *ngSwitchCase="Apache Cordova">Apache Cordova</span>
    <span *ngSwitchCase="TypeScript">TypeScript</span>
    <span *ngSwitchCase="Angular 2">Angular 2</span>
    <span *ngSwitchCase="Ionic 2">Ionic 2</span>
    <span *ngSwitchDefault>Other</span>
</span>

ngIf

<div *ngIf="technology">Technology used is {{ technology.name }}</div>

ngStyle

these inline styles like the following:

elementStyles() {
    let styles = {
    'color': 'rgb(68, 68, 68)',
    'font-weight': 'bold',
    'font-size': '1.1em'
    };
    return styles;
    }

We could then use a property binding to add these inline styles to a HTML element in our template like so:

<div [ngStyle]="elementStyles()">
    Text content will now be bold, set at 1.1em’s in size and rendered in charcoal
    black.
</div>

ngClass

Here’s how this process might look across a page component’s Sass, TypeScript and HTML fles (changes highlighted in bold):

// 1 - src/pages/home/home.scss
page-home {
    .isSuccess {
    color: #1E88E5 !important;
    }
    .isError {
    color: #D43669 !important;
    }
    .isWarning {
    color: #d4d34f !important;
    }
    .canProceed {
    background-color: #deeae8;
    }
}
// 2 - src/pages/home/home.ts
export class HomePage {
    ...
    public isSuccess: boolean;
    public isError: boolean;
    public isWarning: boolean;
    public canProceed: boolean;
    
    constructor(public navCtrl: NavController) {
        ...
        this.isSuccess = true;
        this.isError = false;
        this.isWarning = false;
        this.canProceed = true;
    }

    elementClasses() {
        let classes = {
        isSuccess: this.isSuccess,
        isError: this.isError,
        isWarning: this.isWarning,
        canProceed: this.canProceed
        };
        return classes;
    }
    ...
}

~~~html
// 3 - src/pages/home/home.html
<ion-content padding>
<ion-list>
<ion-item *ngFor="let page of pages" (click)="setNavigationLink(page.link)"
[ngClass]="elementClasses()">

we only wanted to attach the isSuccess CSS class to each iterated item in our home page template we would use a class binding like so (highlighted in bold):

<ion-item *ngFor="let page of pages" (click)="setNavigationLink(page.link)"
[class.isSuccess]="isSuccess">

Theming Ionic 2 apps

Plugin

Loading Data

Forms & Data Input

Data Storage

Animations

Troubleshooting your Ionic 2 App

Debugging & Profling Apps

Documenting your code

Preparing apps for release

Code signing for iOS & Android

Submitting your iOS app to the Apple App Store

Submitting your Android App to the Google Play Store

Case Study #1 Movies App

Case Study #2 SoopaDoopaGames App

Case Study #3 AppyMapper App

⚠️ **GitHub.com Fallback** ⚠️