Mastering Ionic 2 The Definitive Guide - huang-qing/ionic3-platform GitHub Wiki
- Apache Cordova (version 5+)
- Node JS (version 5+)
- NPM (Node Package Manager - version 3+)
- Xcode (for iOS app development)
- Android SDK (for Android development)
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
npm install -g ionic cordova
npm install -g ionic cordova
mkdir apps
chmod -R 775 apps
cd apps
ionic start myApp blank --v2
- 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
// 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).
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
-
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
- 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
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) {}
}
-
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){ }
-
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.
-
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
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);
}
}
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)
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);
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() {
}
}
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 anopenPage
function that is passed the page object from the loop
@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 theNavController
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 thesrc/app/app.html
template using thengFor
directive) -
The openPage function uses the
setRoot
method of theNavControlle
class to avoid usability issues with the back button being displayed when a side menu navigation option is selected
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
<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
https://angular.io/docs/ts/latest/guide/template-syntax.html#!#star-template
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>
<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>
<div *ngIf="technology">Technology used is {{ technology.name }}</div>
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>
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">