
How it works...
There is actually a lot of new information and a lot of concepts in this simple app. At a higher level, this is how the app is structured:
- When you run the app, Cordova loads the /www/index.html file to open first. All of your code and templates are combined into one file, /www/build/main.js.
- The /app folder is where most of your logic belongs. It starts with app.component.ts as the Bootstrap file.
- Each subfolder under the /pages folder will represent a page, which is a new concept in Ionic. A page consists of an HTML template, TypeScript code, and an .scss file to customize that specific template only.
- The /theme folder will contain variables and customizations at a global level to override the default theme from Ionic.
Now, let's start with everything inside the /app folder.
The app.component.ts file only imports all the required pages and components to start the app. This example needs the following four imports by default:
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { TabsPage } from '../pages/tabs/tabs';
You must always import Component, Platform, and StatusBar from Ionic, because that will give you the @Component decorator to Bootstrap your app. A decorator is placed in front of its class to provide metadata for the class. The following example shows that the MyApp class has the characteristics of a component with a template property:
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = TabsPage;
constructor(platform: Platform, statusBar: StatusBar, splashScreen:
SplashScreen) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
});
}
}
Since this is a simple example, you don't need to declare much except the template information. Similar to Ionic 1, you can use either template or templateUrl to point to a local file. In our case, it is app.html and it has the following content:
<ion-nav [root]="rootPage"></ion-nav>
Classes are another new concept in ES6. However, developers have been declaring classes in various programming languages, such as Java and C#. In ES6, you can use classes to be able to efficiently reuse code with better abstraction. A class could exist within that file context only. Consider the following example:
class Example {}
However, if you want to use that class somewhere else, you have to export:
export class Example {}
In a class, you can have the following:
- A variable, such as this.a or this.b
- A method, such as doSomething()
- A constructor that automatically executes (or initializes) when an object is created using the class
Another nice thing about ES6 is the arrow function, as shown:
platform.ready().then(() => { });
The preceding is the same as:
platform.ready().then(function() { });
An example (by passing a parameter) is as follows:
var a1 = a.map( s => s.length );
The same code can be rewritten as shown:
var a1 = a.map(function(s){ return s.length });
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions.
One important thing in app.component.ts is that you must declare a root page. You can see that from the template via [root]="rootPage", and then again in the constructor via this.rootPage = TabsPage. The square brackets, [], around root mean that it's a property of that DOM node. This is a new concept from Angular as it's trying to get rid of using a DOM property, such as ngmodel (which tends to result in lower performance). The assignment here is to tell Ionic 2 that you will use TabsPage, which was imported earlier, and assign that as a root page. Then, the ion-nav directive will look at its own root property to start rendering the page. There seem to be a lot of abstractions and boilerplate compared to Ionic 1. However, this practice is recommended to ensure better separation and scaling.
Once you understand how app.component.ts works, it's easier to grasp the concepts from the other pages. Let's take a look at the /pages/tabs/tabs.ts file, because that's where you define the TabsPage class. From this file, you need to import three other pages, which are the following:
import { Component } from '@angular/core'; import { HomePage } from '../home/home'; import { AboutPage } from '../about/about'; import { ContactPage } from '../contact/contact';
The template for this page is in tabs.html. However, you could also put the template in a string inside the .ts file, as follows:
@Component({ template: ` <ion-tabs> <ion-tab [root]="tab1Root" tabTitle="One"
tabIcon="water"></ion-tab><ion-tab [root]="tab2Root" tabTitle="Two"
tabIcon="leaf"></ion-tab><ion-tab [root]="tab3Root"
tabTitle="Three"
tabIcon="flame"></ion-tab> </ion-tabs>` })
ES6 also introduces a new feature, called a multiline template string. You probably realize that the preceding template string does not have any join() or string combine (+) operators. The reason is that you can use back-tick (` `) to allow a multiline template.
So, instead of doing this:
console.log("string text line 1\n"+ "string text line 2");
You can now do this:
console.log(`string text line 1 string text line 2`);
Below the page decorator, you need to export TabsPage (so that you can use it in app.component.ts) and tell the constructor to use tab1Root, tab2Root, and tab3Root as the roots for other pages in the tab navigation, as shown:
export class TabsPage { tab1Root: any = HomePage; tab2Root: any = AboutPage; tab3Root: any = ContactPage; constructor() { } }
Ionic tab declaration is very similar to Ionic 1, shown as follows:
<ion-tabs> <ion-tab><ion-tab> </ion-tabs>
You just have to make sure that the root property is pointing to another page.
tab1Root is actually very simple to understand, because it's a text page where you add your own content and design within the <ion-content> element, as shown:
<ion-content padding> <h2>Welcome to Ionic 2 Tabs!</h2> <p> This starter project comes with simple tabs-based layout for
apps that are going to primarily use a Tabbed UI. </p> </ion-content>
If you want to change the title, you can simply change the following line:
<ion-title>One</ion-title>
tab2Root and tab3Root are very similar in terms of how they are structured. Ionic gives you the convenience of binding to an event right in the AboutPage class, as shown:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; @Component({ selector: 'page-about', templateUrl: 'about.html' }) export class AboutPage { constructor(public navCtrl: NavController) { } ionViewWillEnter() { console.log('Enter Page 2'); } }
In the preceding example from about.ts, if the user enters tab2Root, it will call the ionViewWillEnter() function automatically. This is a significant improvement because, in Ionic 1, you had to use $ionicView.enter on the $scope variable. Again, the concept of $scope no longer exists in Angular.
For a scalable app, it's better to separate templates into different files and avoid co-mingling templates inside the JavaScript code. templateUrl must always point to the relative location of the .html file.
In ./src/pages/contact/contact.html, you can use the slider box and bind to slide the change event, as shown:
<ion-header>
<ion-navbar>
<ion-title>
Three
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-slides #mySlider index=0 (ionSlideDidChange)="onSlideChanged($event)">
<ion-slide style="background-color: green">
<h2>Slide 1</h2>
</ion-slide>
<ion-slide style="background-color: blue">
<h2>Slide 2</h2>
</ion-slide>
<ion-slide style="background-color: red">
<h2>Slide 3</h2>
</ion-slide>
</ion-slides>
</ion-content>
To get an event in Angular (or Ionic), you have to use parentheses, ( ), because the concept of ng-click or similar is no longer available. In this case, if the slide is changed based on ionSlideDidChange, the ion-slides directive will trigger the onSlideChanged() function in the ContactPage class.
You cannot really run the TypeScript directly without having TypeScript to transpile the code into JavaScript. This process happens automatically behind the scenes when you run ionic serve. Also, when you change some code in the project, Ionic will detect those changes and rebuild the files before updating the browser. There is no need to hit refresh every time.