The Ionic Framework: $ NPM Install - G Cordova

Download as pdf or txt
Download as pdf or txt
You are on page 1of 32

The ionic framework​ enables creation of cross platform mobile applications with HTML, CSS

and JAVASCRIPT(Angular). Ionic 1 was built with Angular 1 and Ionic 2 is based on Angular 2.

WHAT WE’LL BE BUILDING?

We will build a simple app that consumes the ​Github API​ . Our app will list github users, offer a
search box for searching users and be able to view number of followers, repos and gists the
user has.

Our finished app will look like this:

1. INSTALL IONIC 2
a. Ionic 2 is built on top of Cordova, a framework that enables development for
cross platform apps with HTML, CSS and JavaScript. Make sure you have
nodejs​ installed
b. Install Cordova
$ npm install -g cordova

c. For Mac/Linux/Unix users, if you see errors with EACCESS, you can run the
command as root user with sudo npm install -g cordova, or ​just fix your npm
permissions​.
d. Install Ionic CLI
$ npm install -g ionic
e. If you see errors you don't understand, you may want to uninstall previous
versions of ionic-cli with ​npm uninstall -g ionic​, clear your cache with ​npm
cache clean​ and then now install ionic-cli with ​npm install -g ionic​. This installs
the Ionic CLI into your workstation, and now we are good to go.
f. To check the details of your installed ionic, simply run
$ ionic info
g. You should see results almost similar to this:

h. You can ignore the warnings for now. Most of them are only necessary when we
want to deploy or build to either ios or android.
i. Finally, we need to have TypeScript. TypeScript is a superset of JavaScript, and
works really well with Angular 2.
$ npm install -g typescript
2. Hello Ionic 2
a. Ionic 2 provides a simple starter template to quickly scaffold a simple app. Our
app will be called githubIonic, and so we'll quickly scaffold it with the ionic cli.
b. In your terminal:
$ ionic start githubIonic tutorial --v2
c. The above command scaffolds an ionic project based on a tutorial template ionic
provides. It then downloads the necessary npm packages. We'll build the
application using TypeScript, and that's why we have a --ts flag.
d. Go to the githubIonic directory with ​cd githubIonic​. We'll serve the app first, then
go through the folder structure. In your terminal, run:
$ ionic serve
e. You may be asked to select how you would like to serve the ionic app, select
localhost:8100 option. Open ​http://localhost:8100​ in your browser, it should
looks something similar to this.

f. Notice that I have opened my Chrome Dev Tools, and on the top left part, clicked
on the devices Icon so that my app is displayed on a device screen. In this case,
the Galaxy S5.
g. To see the app rendered in all mobile platforms, you can run
$ ionic serve -l
h. It should open your browser, but if not, visit ​http://localhost:8100/ionic-lab

i. You can play around with the app.


3. Ionic 2 project Structure
a. When you first generate an ionic 2 app, This is the generated project structure
├── config.xml
├── hooks
├── ionic.config.json
├── node_modules
├── package.json
├── platforms
├── plugins
├── resources
├── src
├── tsconfig.json
├── tslint.json
b. We will almost always spend 90% of the time in the src folder, as that's where the
application logic is. The whole app however is usually loaded from a simple
src/index.html file, which during build is copied to a new folder www. This is the
view of src/index.html file.
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Ionic App</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0,
minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">

<link rel="icon" type="image/x-icon" href="assets/icon/favicon.ico">


<link rel="manifest" href="assets/manifest.json">
<meta name="theme-color" content="#4e8ef7">

<!-- un-comment this code to enable service worker


<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('assets/service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.log('Error', err));
}
</script>-->

<link href="build/main.css" rel="stylesheet">


</head>

<body>

​<!-- Ionic's root component and where the app will load -->
​<ion-app></ion-app>

​<!-- cordova.js required for cordova apps -->


​<script src=​"cordova.js"​></script>

​<!-- The polyfills js is generated during the build process -->


​<script src=​"build/polyfills.js"​></script>

​<!-- The bundle js is generated during the build process -->


​<script src=​"build/main.js"​></script>

</body>
</html>
c. We'll almost never touch this file. Notice the ​<ion-app></ion-app>​: this is the
entry point for our ionic app. It's called the root component of our app.
d. We'll see where it's defined shortly, but this is how Angular 2 apps are built.
There is always a <root-component></root-component> kind of structure in the
index.html page. The other parts of this file are just loading ionic build
dependencies.
e. Another interesting part of this file is the service worker script tag that is
commented out. ​Service Workers​ are out of scope for this tutorial, but they
enable offline capabilities when it comes to web apps, and come in handy when
building progressive web apps.
f. I'll briefly describe the other project structure.
i. config.xml​ - This contains configurations like the app name, and the
package name, that will be used to install our app into an actual device.
ii. src​ - This is where we'll spend the most of our time building our app. It
contains the structured source code of our app.
iii. node_modules​ - Contains the npm packages listed in the package.json
file. These are packages necessary for building the ionic app.
iv. platforms​ - This is where platform specific builds, build tools and
packages/libraries are stored. You will find a folder for the platform your
are building on. To add a platform, android for example, simply run ​ionic
platform add android​, and this will add the folder android folder to this
folder.
v. plugins​ - This is where ​cordova plugins​ will be stored when they are
installed. Cordova plugins enables your app to have native functionality in
the mobile device, e.g accessing the media storage of the device, or even
the bluetooth API.
vi. resources​ - This also contains platform specific resources, such as icons
and splash screens.
g. The src/app/app.component.ts is the root component of our app. It is
loaded/declared in the src/app/app.module.ts, which simply represents our whole
app as a module, which is the loaded in the app/main.dev.ts or app/main.prod.ts,
depending on which build you do. This structure supports [Ahead of Time
Compilation], an angular 2 feature that offloads compilation from the app bundle.
h. The src/app/app.html file is the root view for our application. In this case it holds a
side menu.
i. If you are familiar with Angular 2, this should be straight foreward, if not, we'll
cover some basics of this structure as we go.
j. An Ionic 2 app is usually divided into page components which are contained in
the src/pages directory. You could think of them as what page is viewable on the
screen at a particular given time (An Activity for Android Developers). The
concept is actually interesting, because pages in ionic 2 are put in a stack, one
on top of each other, and navigation back is as simple as removing the top most
page in the stack (Last In First Out).
k. The src/themes folder contains sass files that help in theming the application.
l. Finally, let's take a closer look at the ​src/app/app.module.ts
import​ { NgModule } ​from​ ​'@angular/core'​;
import​ { IonicApp, IonicModule } ​from​ ​'ionic-angular'​;
import​ { MyApp } ​from​ ​'./app.component'​;
import​ { HelloIonicPage } ​from​ ​'../pages/hello-ionic/hello-ionic'​;
import​ { ItemDetailsPage } ​from​ ​'../pages/item-details/item-details'​;
import​ { ListPage } ​from​ ​'../pages/list/list'​;

@NgModule({
declarations: [
MyApp,
HelloIonicPage,
ItemDetailsPage,
ListPage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,

HelloIonicPage,
ItemDetailsPage,
ListPage
],
providers: []
})
export​ ​class​ ​AppModule​ {}
m. Since we are using this Angular 2 module structure, we need to declare before
hand all the components, providers, directives or pipes that our application uses.
We will be adding these to this file as we go. You can see that this template
imports all the pages it requires, adds the to the declarations property of the
@NgModule​ and also to the entryComponents property. This is also where we
import our root component defined in the ​src/app/app.component.ts
4. Structure of Our Sample Ionic app
a. We'll make use of the live reloading provided by the Ionic CLI.
$ ionic serve
b. Our Ionic App will have 3 main pages. One for github users, another for github
organizations and another for github repositories. The last two pages are just
views to show that we can navigate with the side bar, they will not have any
content. The github users page, however, will enable you to view the details of
the user.
c. Delete everything in the src/pages folder. Then we'll first quickly create the three
main pages with help from the Ionic CLI. Run these in your terminal
$ ionic g page users
$ ionic g page repos
$ ionic g page organisations
d. This will create three folder with the respective names. ​g​ is an alias for ​generate​,
so you can still do ​ionic generate page pageName​. Go into each of the folders
and replace the content of the html files to look like this.
e. src/pages/users/users.html
<ion-header>
<ion-navbar>
<button ion-button icon-only menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>
Users
</ion-title>
</ion-navbar>
</ion-header>

<ion-content padding>
<h3>Users view page</h3>
</ion-content>
f. src/pages/repos/repos.html
<ion-header>
<ion-navbar>
<button ion-button icon-only menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>
Repos
</ion-title>
</ion-navbar>
</ion-header>

<ion-content padding>
<h3>Repos view page</h3>
</ion-content>
g. src/pages/organisations/organizations.html
<ion-header>
<ion-navbar>
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Organisations</ion-title>
</ion-navbar>
</ion-header>

<ion-content padding>

<h3>Organizations view page</h3>

</ion-content>
h. Ionic 2 comes with some built in components.
i. The ​<ion-navbar>​ is responsible for the navigation bar. We could say it's
the navigation component in this case.
ii. ion-button​ is a built in directive for ionic 2 buttons. This instance has an
icon-only​ directive to show that this is an icon button.
iii. menuToggle​ is a built in directive to help toggle the side menu.
iv. We then have ​<ion-icon>​, which is a component responsible for handling
icons. We simply give it the icon name based on ​this ionic icons list​.
v. The ​<ion-title>​ displays the page title.
vi. The ​<ion-content>​ holds the contents of the page. It has a padding
directive that provides a little padding to the contents.
i. Since we are thinking of these as pages, it would be nice to change the class
names to have a page suffix in them. Update all the three generated pages
typescript files to these.
j. src/pages/users.ts
import​ { Component } ​from​ ​'@angular/core'​;
import​ { NavController } ​from​ ​'ionic-angular'​;

@Component({
selector: ​'page-users'​,
templateUrl: ​'users.html'
})
export​ ​class​ ​UserPage​ {

​constructor​(public navCtrl: NavController) {}

ionViewDidLoad() {
​console​.log(​'Hello Users Page'​);
}
}
k. src/pages/repos.ts
import​ { Component } ​from​ ​'@angular/core'​;
import​ { NavController } ​from​ ​'ionic-angular'​;

@Component({
selector: ​'page-repos'​,
templateUrl: ​'repos.html'
})
export​ ​class​ ​ReposPage​ {

​constructor​(public navCtrl: NavController) {}

ionViewDidLoad() {
​console​.log(​'Hello Repos Page'​);
}
}
l. src/pages/organisations.ts
import​ { Component } ​from​ ​'@angular/core'​;
import​ { NavController } ​from​ ​'ionic-angular'​;

@Component({
selector: ​'page-organizations'​,
templateUrl: ​'organisations.html'
})
export​ ​class​ ​OrganisationsPage​ {

​constructor​(public navCtrl: NavController) {}

ionViewDidLoad() {
​console​.log(​'Hello Organisations Page'​);
}
}
m. The ​ionViewDidLoad()​ method is an ionic life cycle hook. It's fired once an ionic
view has load. Intuitive, right?
n. We'll then add these pages to our side nav. Go to ​src/app/app.component.ts
and we'll make a few chages. If you check closely there is a class property called
pages​. This is what composes the sidenav (ion-menu) view, as show in the
src/app/app.html
<ion-menu [content]=​"content"​>

<ion-header>
<ion-toolbar>
<ion-title>Pages</ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-list>
<button ion-item *ngFor="let p of pages" (click)="openPage(p)">
{{p.title}}
</button>
</ion-list>
</ion-content>

</ion-menu>
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
o. We will not touch this file too, we will just use it as it was generated. The button
has an ​*ngFor="let p of pages"​ directive, this is how Angular 2 performs
repeating in templates. It simply means loop through the pages collection and
generate a template for each item in the collection. So if we change the value of
the ​pages​ property, we change the content of the sidenav (ion-menu).
p. The ​<ion-nav>​ is where the page navigated to is displayed. The ​root​ property is
bound to ​rootPage​ in the page class.
q. To add the correct pages in the sidenav, we'll make a few changes to the
src/app/app.component.ts​ file. I have deleted two import statements
(HelloIonicPage and ListPage) at the top for the pages we deleted, and added
import statements for the pages we created.
r. src/app/app.component.ts
import​ { Component, ViewChild } ​from​ ​'@angular/core'​;

import​ { Platform, MenuController, Nav } ​from​ ​'ionic-angular'​;

import​ { StatusBar } ​from​ ​'ionic-native'​;

import​ { UsersPage } ​from​ ​'../pages/users/users'​;


import​ { ReposPage } ​from​ ​'../pages/repos/repos'​;
import​ { OrganisationsPage } ​from​ ​'../pages/organisations/organisations'​;

@Component({
templateUrl: ​'app.html'
})
export​ ​class​ ​MyApp​ {
​// Commented Out for Brevity
}
s. The ​UsersPage​, ​ReposPage​ and ​OrganisationsPage​ are component classes
that represent the pages that were scaffolded when we generated the individual
pages. You can check them out in ​src/pages/users/users.ts​,
src/pages/repos/repos.ts​ and ​src/pages/organisations/organisations.ts​.
t. We'll then edit the ​pages​ class property to match our new pages.
u. src/app/app.component.ts
// imports commented out for brevity

export​ ​class​ ​MyApp​ {


@ViewChild(Nav) nav: Nav;
​// make UsersPage the root (or first) page
rootPage: any = UsersPage;
pages: ​Array​<{title: string, component: any}>;

​constructor​(public platform: Platform, public menu: MenuController) {


​this​.initializeApp();

​// set our app's pages


​this​.pages = [
{ title: ​'Users'​, component: UsersPage },
{ title: ​'Repos'​, component: ReposPage },
{ title: ​'Organisations'​, component: OrganisationsPage },
];
}

initializeApp() {
​this​.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();
});
}

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);
}
}
v. Notice that the ​rootPage​ class property is set to the ​UsersPage​. Remember that
in the view ​src/app/app.html​ the ​<ion-nav>​ root property was bound to this
rootPage​. This means that the ​UsersPage​ will be shown first when the app
loads.
w. We have changed the value of ​this.pages​ in the constructor to match the pages
that we added.
x. The ​openPage​ method is responsible for opening pages when clicked. If you
look back into the ​src/app/app.html​, we can see that the list of pages of bound to
this method with ​(click)="openPage(p)".​ Takes in a page, and opens it.
y. The final thing we need to do to finish this set up is tell angular about our pages.
This is done in the ​src/app/app.module.ts​ file.
z. Import all the three pages and add them to both the declarations and the
entryComponents properties of the @NgModule. Delete the imports we are not
using
aa. src/app/app.module.ts
import​ { NgModule } ​from​ ​'@angular/core'​;
import​ { IonicApp, IonicModule } ​from​ ​'ionic-angular'​;
import​ { MyApp } ​from​ ​'./app.component'​;

import​ { UsersPage } ​from​ ​'../pages/users/users'​;


import​ { ReposPage } ​from​ ​'../pages/repos/repos'​;
import​ { OrganisationsPage } ​from​ ​'../pages/organisations/organisations'​;

@NgModule({
declarations: [
MyApp,
UsersPage,
ReposPage,
OrganisationsPage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
UsersPage,
ReposPage,
OrganisationsPage
],
providers: []
})
export​ ​class​ ​AppModule​ {}
bb. Running serve in the terminal then going to http://localhost:8100 should output
the app.

5. Getting Github Users


a. We'll create a service for getting Github users from
https://api.github.com/users​. The page lists about 30 of the first github users in
json format.
b. First, we need to create a Github user model. This is a class that holds the
relevant fields we want for a github user, since github offers a lot of details.
Create a folder called ​models​ in the ​src​ folder. This is where we will put our User
model and other models we may wish to create later on. Inside ​src/models​ and
add a file ​user.ts​.
c. src/models/user.ts
// User model based on the structure of github api at
// https://api.github.com/users/{username}
export​ interface User {
login: string;
avatar_url: string;
public_repos: number;
public_gists: number;
followers: number;
following: number;
}
d. We've only included properties we'll need from a github response. Now that we
have our model defined, we can create a github-users provider to enable us pull
the users from github. To generate a provider run the following in your terminal
$ ionic g provider github-users
e. This creates a folder called ​providers​ in the src directory, and a ​github-users.ts
file. We need to add a method to get github users in the generated
github-users.ts​ file. We'll slightly modify the generated
src/providers/github-users.ts​ file
import​ { Injectable } ​from​ ​'@angular/core'​;
import​ { Http } ​from​ ​'@angular/http'​;
import​ { Observable } ​from​ ​'rxjs/Rx'​;
import​ ​'rxjs/add/operator/map'​;

import​ { User } ​from​ ​'../models/user'​;

@Injectable()
export​ ​class​ ​GithubUsers​ {
githubApiUrl = ​'https://api.github.com'​;

​constructor​(public http: Http) { }

​// Load all github users


load(): Observable<User[]> {
​return​ ​this​.http.get(​`${​this​.githubApiUrl}/users`​)
.map(​res​ => <User[]>res.json());
}
}
f. The ​@Injectable()​ decorator is how Angular 2 declares it's services/providers.
g. The O​ bservable​ import is necessary for because we will return the results of the
github API call as an observable. Think of an observable as a stream of data we
can subscribe to.
h. The first thing we did was to import the user model with ​import {User} from
'../models/user'
i. Then we add a function ​load​ which will return an Observable
j. We make a request to the github api, and parse the json response with
res.json()​, which we then cast as an array of users with ​<User[]>res.json()​. This
is returned as an observable, which we'll subscribe to to see the users.
k. To use our service in the whole app, we need to add it to the
src/app/app.module.ts​ file.
// Imports commented out for brevity

import​ { GithubUsers } ​from​ ​'../providers/github-users'​;

@NgModule({
declarations: [
​// Declarations commented out for brevity
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
​// Entry Components commented out for brevity
],
providers: [GithubUsers] ​// Add GithubUsers provider
})
export​ ​class​ ​AppModule​ {}
l.
We simply import the GithubUsers and add it in the providers property of the
NgModule.
6. Viewing Github Users
a. Now that we have our users, it's time to view them in the users page. Before we
can do this, we need to test whether we get users from our provider.
b. Open ​src/pages/users/users.ts​ file and make it look like this.
import​ { Component } ​from​ ​'@angular/core'​;
import​ { NavController } ​from​ ​'ionic-angular'​;

import​ { User } ​from​ ​'../../models/user'​;

import​ { GithubUsers } ​from​ ​'../../providers/github-users'​;

@Component({
selector: ​'page-users'​,
templateUrl: ​'users.html'
})
export​ ​class​ ​UsersPage​ {
users: User[]

​ onstructor​(public navCtrl: NavController, private githubUsers:


c
GithubUsers) {
githubUsers.load().subscribe(​users​ => {
​console​.log(users)
})
}
}
c. First, we've imported the GithubUsers Provider at the top with ​import
{GithubUsers} from '../../providers/github-users';​. We've also import the ​User
model.
d. In the constructor of our ​UsersPage​, we've added ​githubUsers: GithubUsers
as one of the parameters. This is how we inject dependencies in Angular 2. We
then call the load function in the constructor and log the result with ​console.log​.
e. Make sure ionic server is running, if not, run ​ionic serve​ in your terminal, then
head over to ​https://localhost:81000​, and open the console panel in Chrome
Dev Tools .

f. You should see that an array of objects has been logged to our console, and on
further inspection, it has almost all the properties of our user model.
g. To view the users in our view page, we need a local variable in the UserPage
class that will be an array of Users. That is why we added ​users: User[]​, just
after the class declaration. We'll assign it the the response of the githubUsers
service call.
h. src/pages/users/users.ts
// Imports commented out for brevity

@Component({
​// Commented out for brevity
})
export​ ​class​ ​UsersPage​ {
users: User[]
​ onstructor​(public navCtrl: NavController, private githubUsers:
c
GithubUsers) {
githubUsers.load().subscribe(​users​ => {
​this​.users = users;
})
}
}
i. We now edit the html view to display the github users.
j. src/pages/users/users.html
<ion-header>
<!-- ion-header contents commented out for brevity -->
</ion-header>

<ion-content padding>
<ion-list>
<button ion-item *ngFor="let user of users">
<ion-avatar item-left>
<img [src]="user.avatar_url">
</ion-avatar>
<h2>{{ user.login }}</h2>
<ion-icon name="arrow-forward" item-right></ion-icon>
</button>
</ion-list>
</ion-content>
k. The ​ion-list​ component is used to render lists in ionic.
l. The items in the list have an ​ion-item​ directive which we will loop through with
Angular 2's built in ​*ngFor​ template directive. We loop through all of the users
with ​*ngFor="let user of users"​. users here refers to the UsersPage class
property users
m. We then use property binding to load the avatar within ​ion-avatar​, which just
adds a rounded border to the image. Remember our user model had an
avatar_url​ property, hence the ​user.avatar_url​.
n. We then add the user's github username, which in this case is ​{{user.login}}​.
o. The ​ion-icon​ is used for loading ionic icons. You simply give the name of the
icon you'd like to use. In this case it's ​arrow-forward​.
p. The ​item-right​ directive puts the icon to the far right of the list item.
q. Spin up the server if it's not running with ​ionic serve​ in your terminal, the head
over to ​http://localhost:8100​. You should see this.

7. Viewing User Details


a. Next, we'll create the details view for users which will be reached by clicking on a
particular user in the list of users.
b. Using the Ionic CLI, create a new page called ​user-details
$ ionic g page user-details
c. A ​user-details​ folder is created inside pages folder, and has three files, the
page's html, the ts and the scss for styling.
d. Rename the class in ​src/app/pages/user-details/user-details.ts​ to
UserDetailsPage​. This is not necessary, it's just a preference.
import​ { Component } ​from​ ​'@angular/core'​;
import​ { NavController } ​from​ ​'ionic-angular'​;

@Component({
selector: ​'page-user-details'​,
templateUrl: ​'user-details.html'
})
export​ ​class​ ​UserDetailsPage​ {
​constructor​(public navCtrl: NavController) {}

ionViewDidLoad() {
​console​.log(​'Hello UserDetails Page'​);
}
}
e. Before we do anything we need to make sure that by clicking a user, this page is
loaded.
f. We first add the page to the ​src/app/app.module.ts​ file.
// Other imports

import​ {UserDetailsPage } ​from​ ​'../pages/user-details/user-details'​;

@NgModule({
declarations: [
​// OtherPages,
UserDetailsPage ​// Add UserDetailsPage here
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
​// Other Pages,
UserDetailsPage ​// Add UserDetailsPage here
],
providers: [GithubUsers]
})
export​ ​class​ ​AppModule​ {}
g. Then let's make a few changes to the user-details page template.
h. src/pages/user-details/user-details.html
<ion-header>
<ion-navbar>
<ion-title>{{login}}'s details</ion-title>
</ion-navbar>
</ion-header>

<ion-content padding >


<h3>User Details view page</h3>
</ion-content>
i. We've put in a ​{{login}}​ in the view title, because we intend to pass the user to
this view.
j. Next, we'll go to the Users page and add a navigation to the user-details page.
k. src/pages/users/users.ts
// Other Imports
import​ { UserDetailsPage } ​from​ ​'../user-details/user-details'​;

@Component({
selector: ​'page-users'​,
templateUrl: ​'users.html'
})
export​ ​class​ ​UsersPage​ {
users: User[]

​ onstructor​(public navCtrl: NavController, private githubUsers:


c
GithubUsers) {
​// Commented out for brevity
}

goToDetails(login: string) {
​this​.navCtrl.push(UserDetailsPage, {login});
}
}
l. First of all we import the UserDetailsPage at the top with ​import
{UserDetailsPage} from '../user-details/user-details'​.
m. We then add a method that will handle the navigation, ​goToDetails​. It takes in a
login (username) as a parameter.
n. Ionic 2 treats navigation as a stack, meaning pages are added on top of each
other. That is why you see the ​this.navCtrl.push​, and we push a page into the
navigation stack. Going back or pressing the back button is like popping the last
element in the stack (Last In First Out). The second parameter of the push is the
object we wish to pass to the next page.
o. {login}​ is a es2015 property shorthand. In es5, this translates to ​{login: login}​.
p. Finally, we need to call this ​goToDetails​ in the view.
q. src/pages/users/users.html
<!-- ion-header -->
<ion-content padding>
<ion-list>
<button ion-item *ngFor="let user of users"
(click)="goToDetails(user.login)">
<!-- ion-item content-->
</button>
</ion-list>
</ion-content>
r. All we've done is add ​(click)="goToDetails(user.login)"​ in the next to the
*ngFor directive.And finally, we need to get the user passed to the details page.
s. src/pages/user-details/user-details.ts
import​ { Component } ​from​ ​'@angular/core'​;
import​ { NavController, NavParams } ​from​ ​'ionic-angular'​;

@Component({
selector: ​'page-user-details'​,
templateUrl: ​'user-details.html'
})
export​ ​class​ ​UserDetailsPage​ {
login: string;

​constructor​(public navCtrl: NavController, private navParams: NavParams)


{
​this​.login = navParams.get(​'login'​);
}
}
t. We've simply added ​NavParams​ to the existing imports to enable us access the
navigation parameters.
u. Then, declared a ​login​ property of type ​string​. Remember this represents the
username.
v. We inject the NavParams provider in the constructor as ​navParams​, which we
then use to get the value of the passed parameter from the previous page with
this.login = navParams.get('login')​ . This should update the user's
login/username correctly in our details view.
w. If you go to ​http://localhost:8100​, you should be able to click on a user and see
this.

x. The username/login of the user you clicked should be the as a title in the view.
8. Get correct user details
a. Now that we have the user in our details view, we need to get his specific details.
To do this we need to edit the ​GithubUsers​ provider to handle the request. The
request will be made to ​https://api.github.com/users/{login}​, where we pass in
the username/login as the last parameter.
b. src/providers/github-users.ts
// Imports

@Injectable()
export​ ​class​ ​GithubUsers​ {
githubApiUrl = ​'https://api.github.com'​;

​constructor​(public http: Http) { }

​// Load all github users


load(): Observable<User[]> {
​// Load users
}

​// Get github user by providing login(username)


loadDetails(login: string): Observable<User> {
​return​ ​this​.http.get(​`${​this​.githubApiUrl}/users/${login}`​)
.map(​res​ => <User>(res.json()))
}
}
c. We've added an almost identical method to the initial ​load()​ called ​loadDetails()​.
It takes in a string login as a parameter and returns an Observable of User, that
we can subscribe to, to get the results of the request. It casts the response to the
User model with ​<User>res.json()​.
d. The ​http.get​ request is sent to ​${this.githubApiUrl}/users/${login}​. This is ES6
template strings, also available in typescript. It Involves using backticks, the key
below the escape key on the keyboard, and passing any values with the ​${var}
syntax, and it will revolve to a valid string.
e. Now, we go to the user-details page and get the correct user details.
f. src/pages/user-details/user-details.ts
// Other imports

import​ { User } ​from​ ​'../../models/user'​;

import​ { GithubUsers } ​from​ ​'../../providers/github-users'​;

@Component({
selector: ​'page-user-details'​,
templateUrl: ​'user-details.html'
})
export​ ​class​ ​UserDetailsPage​ {
user: User;
login: string;

​ onstructor​(public navCtrl: NavController, private navParams: NavParams,


c
private githubUsers: GithubUsers) {
​this​.login = navParams.get(​'login'​);
githubUsers.loadDetails(​this​.login).subscribe(​user​ => {
​this​.user = user;
​console​.log(user)
})
}
}
g. We've first of all imported the GithubUsers provider with ​import {GithubUsers}
from '../../providers/github-users';​.
h. We then import the user model with ​import {User} from '../../models/user'​;
i. We then inject it in the constructor as ​githubUsers​ then call the
githubUsers.loadDetails​ with the value retrieved from the navigation params
login​. We assign the results to the class property 'user', then log the results, just
for debugging purpose.
j. Go to ​http://localhost:8100​, and click on a user, you should see this.

k. If you expand the logged object, you'll see it has the properties of our user model.
9. Display user details
a. Now that we have the details of the user, we should display them in the view.
We'll only display the followers, following, public repos and public gist numbers.
b. Let's remove the ​console.log​ from the ​user-detail.ts file​.
c. Since we already added ​this.user = user​, to assign the result to the class' user
property, we can now create a view by editing the page's template html.
d. app/pages/user-details/user-details.html
<!-- ion-header -->

<ion-content padding >


<ion-list>
<ion-item>
<ion-label>Followers</ion-label>
<ion-badge item-right>{{user?.followers}}</ion-badge>
</ion-item>
<ion-item>
<ion-label>Following</ion-label>
<ion-badge item-right>{{user?.following}}</ion-badge>
</ion-item>
<ion-item>
<ion-label>Repos</ion-label>
<ion-badge item-right>{{user?.public_repos}}</ion-badge>
</ion-item>
<ion-item>
<ion-label>Gists</ion-label>
<ion-badge item-right>{{user?.public_gists}}</ion-badge>
</ion-item>
</ion-list>
</ion-content>
e. The ​user?.property​ just tells angular that u
​ sers​ may be null initially, so that an
undefined error is not thrown.
f. I've used an ​ion-badge​ and an ​ion-label​ to view the user data. Go to
http://localhost:8100​, and you should see this. Then click on any user.

10. Search for Users


a. This is the final feature of our app. We'll start by adding a search box at the top of
the users page. Ionic 2 provides a custom searchbar component and that's what
we'll use.
b. src/pages/users/users.html
<!--HTML commented out ​for​ brevity-->

<ion-content padding>
<ion-searchbar></ion-searchbar>
<ion-list>
<!--HTML commented out for brevity-->
</ion-list>
</ion-content>
c. We've added a search bar with <ion-searchbar>, and should have a searchbar at
the top of the page.

d. The logic behind searching is simple. Since we have a list already, we'll just
update the list with our result. The github api enables you to search through the
following url structure ​https://api.github.com/search/users?q={searchParam}​,
with a ​searchParam​.
e. We'll first of all create a provider method for search in our GithubUsers Provider.
The method is also almost similar to the ​load()​ method.
f. src/providers/github-users.ts
// Imports

@Injectable()
export​ ​class​ ​GithubUsers​ {
githubApiUrl = ​'https://api.github.com'​;

​constructor​(public http: Http) { }

​// Load all github users


load(): Observable<User[]> {
Load Users
}

​// Get github user by providing login(username)


loadDetails(login: string): Observable<User> {
​// Load Details
}

​ / Search for github users


/
searchUsers(searchParam: string): Observable<User[]> {
​return
this​.http.get(​`${​this​.githubApiUrl}/search/users?q=${searchParam}`​)
.map(​res​ => <User[]>(res.json().items))
}
}
g. The ​searchUsers​ method takes in a search parameter, which it will pass to the
api url. We then return a Observable of type ​User[]​ (Array of users) like we did
initially for the ​load​ method.
h. To test our search method, go to the users page.
i. src/pages/users/users.ts
// Imports

@Component({
selector: ​'page-users'​,
templateUrl: ​'users.html'
})
export​ ​class​ ​UsersPage​ {
users: User[]

​constructor​(public navCtrl: NavController, private githubUsers:


GithubUsers) {
​// Load GithubUsers

githubUsers
.searchUsers(​'scotch'​).subscribe(​users​ => {
​console​.log(users)
});
}
​// goToDetails
}
j. The ​githubUsers.searchUsers('scotch')​ in the constructor should send a
search request to github and return results. Go to ​http://localhost:8100​.

k. Notice that I've circled two of the logins for the results, and they both have
scotch​ in the login property.
11. Simple Search
a. We'll only search when three or more characters have been typed. Let's capture
the value typed in from the user in the search bar.
b. src/pages/users/user.html
<!-- HTML commented out ​for​ brevity -->

<ion-content padding >


<ion-searchbar (input)="search($event)"></ion-searchbar>
<ion-list>
<!-- HTML commented out for brevity -->
</ion-list>
</ion-content>
c. We've added an ​(input)="search($event)"​ in the ​ion-searchbar​ to capture the
input event for the search bar. Angular 2 binds to events through ​(event)​ syntax.
d. src/pages/users/users.ts
// Imports commented out for brevity

@Component({
selector: ​'page-users'​,
templateUrl: ​'users.html'
})
export​ ​class​ ​UsersPage​ {
users: User[]
originalUsers: User[];

​ onstructor​(public navCtrl: NavController, private githubUsers:


c
GithubUsers) {
githubUsers.load().subscribe(​users​ => {
​this​.users = users;
​this​.originalUsers = users;
})
}

goToDetails(login: string) {
​this​.navCtrl.push(UserDetailsPage, {login});
}

search(searchEvent) {
​let​ term = searchEvent.target.value
​// We will only perform the search if we have 3 or more characters
​if​ (term.trim() === ​''​ || term.trim().length < ​3​) {
​// Load cached users
​this​.users = ​this​.originalUsers;
} ​else​ {
​// Get the searched users from github
​this​.githubUsers.searchUsers(term).subscribe(​users​ => {
​this​.users = users
});
}
}
}
e. We've added an ​originalUsers​ class property, to cache the original results of the
github users fetch.
f. Our search function is structured to only work when the search parameter is of
character length that is greater than 3. We reset the results if this condition is not
met. (This is not robust however, because the user can enter non-alphanumeric
characters, but for learning purposes, will do).
g. Go to http://localhost:8100, and try searching for a term, or a username you
know.

h. Clicking any of the result should take you to that user's profile.
12. Build/Run the application
a. Android
i. You need to have the android sdk setup. The installation instructions for
your specific platform can be ​found here​.
ii. Add android platform to your application
$ ionic platform add android
iii. This adds a folder ​android​ within the ​platforms​ folder in your app and
adds the necessary resources needed to build an android application.
iv. Build the android app
$ ionic build android
v. This builds the application, and puts the built apk in the
platforms/android/build/outputs​ folder.
vi. Run the android app
$ ionic run android
vii. This will run the app in either your default emulator, or a phone connected
to your computer with usb debugging enabled.
b. IOS
i. To build for ios, you need to be using MacOs and have xCode installed.
You also need two node modules installed globally. They just help in
building and deploying the app.
$ npm install -g ios-deploy
$ npm install -g ios-sim version
ii. Add ios platform to your project.
$ ionic platform add ios
iii. This adds a folder ​ios​ within the p
​ latforms​ folder in your app and adds
the necesarry resources needed to build an ios application.
iv. Build your app for ios
$ ionic build ios
v. This builds the application, and puts the build output in the
platforms/ios/build/emulator ​folder.
vi. Then run the application in an ios simulator that comes installed with
xCode
$ ionic run ios

CONCLUSION

Building Ionic 2 Apps is pretty intuitive and cleaner once you have an understanding of how
Angular 2 works. Ionic handles its views as components. You can build an application really
quickly, especially if you have your api already defined somewhere.

You might also like