Build a Mobile App with Angular 2 and Ionic 2
The Ionic Framework enables the creation of cross platform mobile applications with HTML, CSS and JavaScript(Angular). Ionic 1 was built with Angular 1.*, and with the upcoming release of Angular 2, the second major version of Ionic is also imminent.
Ionic 2 is still in beta, but if you are looking to build cross-platform apps quickly, and you already know Angluar 2 or JavaScript, this guide will get you up to speed.
# Why Choose Ionic?
You already know HTML/CSS/JS
You can leverage the skills you already have from developing web applications with HTML, JavaScript and CSS to build cross-platform mobile apps. If you work with Angular 2, this will be a seamless transitions.Take advantage of Progressive Web Apps
Google has been talking about Progressive Web Apps. These are simply web apps that give an app-like user experience to users, and are built with Web Technologies and Ionic 2 is at the fore front of implementing this. An example progressive web app(not built with ionic) is the google io web app: Visit the app in your chrome browser in your phone, click on menu and tap Add to Home Screen. You'll then be able to load it as an app from your home screen.Target all major mobile platforms
If you need to quickly build an app for all major mobile platforms (Android, iOS and Windows Phone), having one codebase may be the fastest way to do it, and Ionic is perfect for such a scenario. Updating the app, or rolling uout updates is just as easy as editing one code base.Native Functionality is easy to implement
There are a lot of cordova plugins that allow you to include native functionality of the platform you are building for. The Ionic 2 documentation has implimentation examples of some of the plugins.# 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 the number of followers, repos, and gists the user has.Below is a short video of the finished app.
# Install Ionic 2
Ionic 2 is built on top of Cordova, a framework that enables development for cross patform apps with HTML, CSS and JavaScript. Make sure you have nodejs installed.Install Cordova
$ npm install -g cordova
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 persmissions..Install Ionic 2 beta
$ npm install -g ionic@beta
This installs ionic 2 and its CLI into your workstation, and now we are good to go.NOTE Ionic 2 is still in beta, and at the time of this article’s publication. To check the version of ionic CLI you have installed, simply run
$ ionic info
You should see results almost similar to this
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.Finally, we need to have TypeScript and Typings installed in our workstation. TypeScript is a superset of JavaScript, and works really well with Angular 2, you can go through the articles by this author to quickly get up to speed with TypeScript. Typings help TypeScript to identify types for non-typescript code.
$ npm install -g typescript
$ npm install -g typings
# Hello Ionic 2
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.In your terminal:
$ ionic start githubIonic tutorial --v2 --ts
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. 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
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.Notice that I have opened my Chrome Dev Tools on the side so that the left part where my app is simulates a mobile screen.
This is just a preference. To see the app in a desired mobile device screen, you can go through Device Mode for Chrome Dev Tools.
You can play around with the app.
Note The version of ionic you are using to build this app is listed in the package.json file as
ionic-angular
.{
"ionic-angular": "2.0.0-beta.10",
}
# Ionic 2 Project Structure
A lot goes into building an Ionic 2 app, but the final build is stored in the www folder. If you look through it, you'll see that it looks just like a web application set up.The www/index.html is usually the entry point of an Ionic App, (and an Angular App), generally all web apps usually have an index.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Ionic</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link ios-href="build/css/app.ios.css" rel="stylesheet">
<link md-href="build/css/app.md.css" rel="stylesheet">
<link wp-href="build/css/app.wp.css" rel="stylesheet">
</head>
<body>
<ion-app></ion-app>
<!-- cordova.js required for cordova apps -->
<script src="cordova.js"></script>
<!-- Polyfill needed for platforms without Promise and Collection support -->
<script src="build/js/es6-shim.min.js"></script>
<!-- Zone.js and Reflect-metadata -->
<script src="build/js/Reflect.js"></script>
<script src="build/js/zone.js"></script>
<!-- the bundle which is built from the app's source code -->
<script src="build/js/app.bundle.js"></script>
</body>
</html>
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. 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 dependencies, both
from vendors/npm, and those built by ionic during development.I'll briefly describe the other folders.
- app - This is where we'll spend the most of our time building our app. It contains the structured source code of our app.
- node_modules - Contains the npm packages listed in the package.json file. These are packages necessary for building the ionic app.
- 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. - 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.
- resources - This also contains platform specific resources.
- typings - This contains files that help TypeScript infer types it is not aware of. Not all JavaScript libraries were written in TypeScript, and for TypeScript to know about them, we'll need these libraries' typings.
We'll examine the app folder, where we'll write most of our code.
app
├── app.html
├── app.ts
├── pages
│ ├── hello-ionic
│ │ ├── hello-ionic.html
│ │ ├── hello-ionic.scss
│ │ └── hello-ionic.ts
│ ├── item-details
│ │ ├── item-details.html
│ │ ├── item-details.scss
│ │ └── item-details.ts
│ └── list
│ ├── list.html
│ └── list.ts
└── theme
├── app.core.scss
├── app.ios.scss
├── app.md.scss
├── app.variables.scss
└── app.wp.scss
The app.html is the view/template for our app component. It's simply the root page where all our app pages will be loaded.The app.ts is the TypeScript file that defines our root App Component. It has a class MyApp defined. We'll look more into this when buidling the app.
An Ionic 2 app is divided into pages which are contained in the 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).
The Themes folder contains sass files that help in theming the application.
# The Structure of our Sample Ionic App
We'll make use of the live reloading provided by the Ionic CLI.$ ionic serve
Our Ionic App will have 3 main pages. One for github users, another
for github organisations 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.Delete everything in the app/pages folder, and clear the content of app/theme/app.core.scss file. 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 organizations
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.app/pages/users/users.html
<ion-header>
<ion-navbar>
<button 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>
app/pages/repos/repos.html<ion-header>
<ion-navbar>
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Users</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding >
<h3>Repos view page</h3>
</ion-content>
app/pages/organizations/organizations.html<ion-header>
<ion-navbar>
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Organizations</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h3>Organizations view page</h3>
</ion-content>
Ionic 2 comes with some built in components. The
<ion-navbar>
is responsible for the navigation bar. We could say it's the navigation component in this case.menuToggle
is a built in directive to help toggle the side menu.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. The
<ion-title>
displays the page title. The
<ion-content>
holds the contents of the page. It has a padding
directive that provides a little padding to the contents.We'll then add these pages to our side nav. Go to app/app.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 view, as show in the app/app.html<ion-menu [content]="content">
<ion-toolbar>
<ion-title>Pages</ion-title>
</ion-toolbar>
<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 id="nav" [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>
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.The
<ion-nav>
is where the page navigated to is displayed. The root
property is bound to rootPage
in the page class. We'll see definition this in detail shortly.To add the correct pages in the sidenav, we'll make a few changes to the app/app.ts file. I have commented out two import statements at the for the pages we deleted, and added import statements for the pages we created. You can delete them if you want instead of commenting them out.
app/app.ts
import {Component, ViewChild} from '@angular/core';
import {ionicBootstrap, Platform, MenuController, Nav} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
// Comment out impor of pages we have deleted from the pages folder
//import {HelloIonicPage} from './pages/hello-ionic/hello-ionic';
//import {ListPage} from './pages/list/list';
import {UsersPage} from './pages/users/users';
import {ReposPage} from './pages/repos/repos';
import {OrganizationsPage} from './pages/organizations/organizations'
@Component({
templateUrl: 'build/app.html'
})
class MyApp {
// Commented out for brevity
}
The UsersPage
, ReposPage
and OrganizationsPage
are component classes that represent the pages that were scaffolded
when we generated the individual pages. You can check them out in app/pages/users/users.ts, app/pages/repos/repos.ts and app/pages/organizations/organizations.ts.We'll then edit the
pages
class property to match our new pages.app/app.ts
// imports commented out for brevity
class MyApp {
@ViewChild(Nav) nav: Nav;
// make UsersPage the root (or first) page
// rootPage: any = UsersPage;
rootPage: any = UsersPage;
pages: Array<{title: string, component: any}>;
constructor(
private platform: Platform,
private menu: MenuController
) {
this.initializeApp();
// set our app's pages
this.pages = [
// Comment out pages we deleted
//{ title: 'Hello Ionic', component: HelloIonicPage },
//{ title: 'My First List', component: ListPage }
{ title: 'Users', component: UsersPage },
{ title: 'Repos', component: ReposPage },
{ title: 'Organizations', component: OrganizationsPage }
];
}
// code commented out for brevity
}
Notice that the rootPage
class property is set to the UsersPage
. Remember that in the view 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.We have changed the value of
this.pages
in the constructor to match the pages that we added.Running serve in the terminal then going to
http://localhost:8100
should output the app.# Getting Github Users
We'll create a service for getting Github users fromhttps://api.github.com/users
. The page lists about 30 of the first github users in json format.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 app folder. This is where we will put our User model and other models we may wish to create later on. Inside app/models and add a file user.ts.
app/models/user.ts
// User model based on the structure of github api at
// https://api.github.com/users/{username}
export class User {
login: string;
id: number;
avatar_url: string;
gravatar_id: string;
url: string;
html_url: string;
followers_url: string;
following_url: string;
gists_url: string;
starred_url: string;
subscriptions_url: string;
repos_url: string;
events_url: string;
received_events_url: string;
type: string;
site_admin: boolean;
name: string;
company: string;
blog: string;
location: string;
email: string;
hireable: string;
bio: string;
public_repos: number;
public_gists: number;
followers: number;
following: number;
created_at: string;
updated_at: string;
}
We will not use all the properties of this model. 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
This creates a folder called providers in the app folder, and another github-users folder with a github-users.ts file.We'll slightly modify the generated app/providers/github-users/github-users.ts file
import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';
// Import the user model
import {User} from '../../models/user'
/*
Generated class for the GithubUsers provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
@Injectable()
export class GithubUsers {
githubUsers: any = null;
constructor(public http: Http) {}
load() {
if (this.githubUsers) {
// already loaded users
return Promise.resolve(this.githubUsers);
}
// don't have the users yet
return new Promise(resolve => {
// We're using Angular Http provider to request the users,
// then on the response it'll map the JSON data to a parsed JS object.
// Next we process the users and resolve the promise with the new data.
this.http.get('https://api.github.com/users')
.map(res => <Array<User>>(res.json()))
.subscribe(users => {
// we've got back the raw users, now generate the core schedule users
// and save the users for later reference
this.githubUsers = users;
resolve(this.githubUsers);
});
});
}
}
The @Injectable()
decorator is how Angular 2 declares it's services/providers. The first thing we did was to import the user model with
import {User} from '../../models/user'
. Then, notice a function
load
has been scaffolded for you
to load the data you want, all you need to do is edit the path to the
json data, which in this case is https://api.github.com/users/
, and call your provider somewhere as GithubUsers.load()
.We changed the line with
this.http.get(''path/to/data.json)
, replace it so that now you have this.http.get('https://api.github.com/users')
. We've also changed the property data
from the scaffolded class to githubUsers
.Finally, we want results from Github to be converted into an array of users. We do this by casting the json result into an array of users with
.map(res => <Array<User>>(res.json()))
, just below the this.http.get('https://api.github.com/users')
.# Viewing Github Users
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.Open app/pages/users/users.ts file and make it look like this.
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
// Import GithubUsers provider
import {GithubUsers} from '../../providers/github-users/github-users';
/*
Generated class for the UsersPage page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
@Component({
templateUrl: 'build/pages/users/users.html',
// Add the GithubUsers provider as part of our page component
providers: [GithubUsers]
})
export class UsersPage {
// Inject the GithubUsers in the constructor of our page component
constructor(public nav: NavController, githubUsers: GithubUsers) {
// Test whether the github provider returns data
githubUsers
.load()
.then(function (users) {
// Log the returned github users
console.log(users)
});
}
}
We've made a few modifications. First, we've imported the GithubUsers Provider at the top with import {GithubUsers} from '../../providers/github-users/github-users';
. Then to use a provider in Angular 2, we need to pass it in the providers property of our component decorator, in this case its the
@Component
. So you'll notice we've providers[GithubUsers]
as one of the properties.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
.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 .
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.To view the users in our view page, we need a local variable in the UserPage class that will be an array of Users. Update your User page component to look like this.
app/pages/users/users.ts
// Imports commented out for brevity
// Import User model
import {User} from '../../models/user';
@Component({
// Commented out for brevity
})
export class UsersPage {
// Declare users as an array of User model
users: User[];
// Inject the GithubUsers in the constructor of our page component
constructor(public nav: NavController, githubUsers: GithubUsers) {
// Test whether the github provider returns data
githubUsers
.load()
// User arrow function notation
.then(users => this.users = users);
}
}
We've made a few updates. First of all, we import the User Model with import {User} from '../../models/user';
at the top. We then decalre a local variable of type Array of Users immedialtely after defining the class,
users: User[];
. This is TypeScript's way of defining the type of the users class property. It means the users property is of type array of User.Finally, we update the result of the GithubUsers provider. We've used the arrow function
then(users => this.users = users)
. This assigns the result of the promise to the local property users.We now edit the html view to display the github users. We'll use an
ion-list
which is a copmonent provided by ionic for rendering lists.app/pages/users/users.html
<ion-header>
<ion-navbar>
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Users</ion-title>
</ion-navbar>
</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 ios="ios-arrow-forward" md="md-arrow-forward" item-right></ion-icon>
</button>
</ion-list>
</ion-content>
The ion-list
component is used to render lists. The items in the list have an
ion-item
directive which we will loop through with Angular 2's built in *ngFor
directive. We loop through all of the users with *ngFor="let user of users"
. We then user 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
.We then add the user's github username, which in this case is
{{user.login}}
. The
ion-icon
is used for loading ionic icons. You could easily use <ion-icon name="arrow-forward"></ion-icon>
but we used ios="ios-arrow-forward" md="md-arrow-forward"
as a way to show how to load platform specific icons, in this case, ios and android. The
item-right
directive puts the icon to the far right of the list item.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.
# Viewing User Details
Next, we'll create the details view for users which will be reached by clicking on a particular user in the list of users.Using the Ionic CLI, create a new page called user-details
$ ionic g page user-details
A user-details folder is created inside pages folder, and has three files, the page's html, the ts and the scss
for styling. Before we do anything we need to make sure that by
clicking a user, this page is loaded. First of all let's make a few
changes.app/pages/user-details/user-details.html
<ion-header>
<ion-navbar>
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>{{login}} Details</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding >
<h3>User Details view page</h3>
</ion-content>
This is just basic html with built in ionic components to show the title of the page. We've however put in a {{login}}
in the view title, because we intend to pass the user to this view.Next, we'll go to the Users page and add a navigation to the user-details page.
app/pages/users/users.ts
// Imports commented out for brevity
// Import User's Details Page
import {UserDetailsPage} from '../user-details/user-details';
@Component({
// Code commented out for brevity
})
export class UsersPage {
// Code commented out for brevity
constructor(public nav: NavController, githubUsers: GithubUsers) {
// Implementation commented out for brevity
}
// Navigate to user details page with the login as a parameter
goToDetails(event, login) {
this.nav.push(UserDetailsPage, {
login: login
});
}
}
First of all we import the UserDetailsPage at the top with import {UserDetailsPage} from '../user-details/user-details'
. We then add a method that will handle the navigation,
goToDetails
. It takes in two arguments, the event, just in case we want to do something with the event that triggered the navigation, and the login(username). Ionic 2 treats navigation as a stack, meaning pages are added on top of each other. That is why you see the
this.nav.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.Finally, we need to raise this
goToDetails
in the view.app/pages/users/users.html
<!-- HTML commented out for brevity -->
<ion-content padding>
<ion-list>
<button ion-item *ngFor="let user of users" (click)="goToDetails($event, user.login)">
<!-- HTML commented out for brevity -->
</button>
</ion-list>
</ion-content>
All we've done is add (click)="goToDetails($event, user.login)"
in the next to the *ngFor directive.And finally, we need to get the user passed to the details page.
app/pages/user-details/user-details.ts
import { Component } from '@angular/core';
// Add NavParams to get the naviagtion parameters
import { NavController, NavParams } from 'ionic-angular';
/*
Generated class for the UserDetailsPage page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
@Component({
templateUrl: 'build/pages/user-details/user-details.html',
})
export class UserDetailsPage {
login: string;
constructor(public nav: NavController, navParams: NavParams) {
// Retrieve the login from the navigation parameters
this.login = navParams.get('login');
}
}
We've simply added NavParams
to the existing imports to enable us access the navigation parameters. Then, declared a
login
property of type string
. 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.If you go to
http://localhost:8100
, you should be able to click on a user and see this.
The username/login of the user you clicked should be the as a title in the view.Get correct user details.
Now that we have the user in our details vew, 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 tohttps://api.github.com/users/{login}
, where we pass in the username/login as the last parameter.app/providers/github-users/github-users.ts
// Imports commented out for brevity
@Injectable()
export class GithubUsers {
githubUsers: any = null;
constructor(public http: Http) {}
load() {
// Implementation commented out for brevity
}
// Get user details from the github api
loadDetails(login: string) {
// get the data from the api and return it as a promise
return new Promise<User>(resolve => {
// Change the url to match https://api.github.com/users/{username}
this.http.get(`https://api.github.com/users/${login}`)
.map(res => <User>(res.json()))
.subscribe(user => {
resolve(user);
});
});
}
}
We've added an almost identical method to the initail load()
called loadDetails()
. It takes in a string as a parameter and returns a promise of type User, hence the return new Promise<User>()
syntax. The
http.get
request is sent to https://api.github.com/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 reolve to a valid string.We then cast the response to a User object and resolve the promise in the observable subscribe method.
Now, we go to the user-details page and get the correct user details.
app/pages/user-details/user-details.ts
// Imports commented out for brevity
// Import GithubUsers Provider
import {GithubUsers} from '../../providers/github-users/github-users';
// Import the User model
import {User} from '../../models/user';
@Component({
templateUrl: 'build/pages/user-details/user-details.html',
//Add GithubUsers provider
providers: [GithubUsers]
})
export class UserDetailsPage {
user: User = new User;
login: string;
constructor(public nav: NavController, navParams: NavParams, githubUsers: GithubUsers) {
// Retrieve the login from the navigation parameters
this.login = navParams.get('login');
// Get the user details and log
githubUsers.loadDetails(this.login)
.then( user => console.log(user))
}
}
We've first of all imported the GithubUsers provider with import {GithubUsers} from '../../providers/github-users/github-users';
. We then import the user model with
import {User} from '../../models/user';
.To use the provider, we have to add it to the providers property of the
@Component
decorator, providers: [GithubUsers]
.
We then inject it in the constructor as githubUsers
then call the githubUsers.loadDetails
with the value retrieved from the navigation params login
. We've decided to log the results. Go to
http://localhost:8100
, and click on a user, you should see this.
If you expand the logged object, you'll see it has the properties of our user model. GithubUsers provider
Notice that we used the GithubUsers twice in our app. Angular 2 is designed to have singleton existence of providers. We can refactor this by declaring GithubUsers provider in our root component/page which is app/app.ts as a provider, and then deleting theproviders: [GithubUsers]
property in all other components. # Display User details
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.Let's remove the
console.log
from the user-detail.ts file, and change it to this.app/pages/user-details/user-details.ts
// Imports commented out for brevity
@Component({
// Commented out for brevity
})
export class UserDetailsPage {
// Commented out for brevity
constructor(public nav: NavController, navParams: NavParams, githubUsers: GithubUsers) {
// Retrieve the login from the navigation parameters
this.login = navParams.get('login');
// Get the user details and log
githubUsers.loadDetails(this.login)
.then( user => this.user = user)
}
}
We've added user => this.user = user
, to assign the result to the class' user property. We can then create a view by editing the htmlapp/pages/user-details/user-details.html
<!--HTML commented out for brevity-->
<ion-content padding>
<h3>User Details view page</h3>
<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>
I've used an ion-list
and an ion-label
to view the user data. Go to http://localhost:8100
, and you should see this.
Clicking on a given user should display hes/her details.# Search for users
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.app/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>
We've added a search bar with <ion-searchbar>
, and should have a searchbar at the top of the page.
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
. We'll first of all create a provider method for search in our GithubUsers Provider. The method is also almost similar to the
loadDetails
methodapp/providers/github-users/github-users.ts
// Imports commented out for brevity
@Injectable()
export class GithubUsers {
// Code commented out for brevity
load() {
// Method implementation commented out for brevity
}
// Get user details from the github api
loadDetails(login: string) {
// Method implementation commented out for brevity
}
// Search for github users
searchUsers(searchParam: string) {
// get the data from the api and return it as a promise
return new Promise<Array<User>>(resolve => {
// Change the url to match https://api.github.com/search/users?q={searchParam}
this.http.get(`https://api.github.com/search/users?q=${searchParam}`)
// Cast the result into an array of users.
// The returned json result has an items
// property which contains the users
.map(res => <Array<User>>(res.json().items))
.subscribe(users => {
resolve(users);
});
});
}
}
The searchUsers
method takes in a search parameter, which it will pass to the api url. We then return a promise of type Array<Users>
like we did initially for the load
method. To test our search method, go to the users page.
app/pages/users/users.ts
// Imports commented out for brevity
@Component({
// Code commented out for brevity
})
export class UsersPage {
// Code commented out for brevity
// Inject the GithubUsers in the constructor of our page component
constructor(public nav: NavController, githubUsers: GithubUsers) {
// Code commented out for brevity
// Test if our seach function works.
githubUsers
.searchUsers('ganga')
.then(users => console.log(users));
}
// Code commented out for brevity
}
The githubUsers.searchUsers('ganga')
in the constructor should send a search request to github and return results. Go to http://localhost:8100
.
Notice that I've circled two of the logins for the results, and they both have ganga
in them.Simple Search
We'll only search when three or more characters have been typed.Let's capture the value typed in from the user in the searchbar.
app/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>
We've added an (input)="search($event)"
in the ion-searchbar
to capture the input event for the searchbar. Angular 2 binds to events through (event)
syntax. app/pages/users/users.ts
// Imports commented out for brevity
@Component({
// Commented out for brevity
})
export class UsersPage {
// Commented out for brevity
// Inject the GithubUsers in the constructor of our page component
constructor(public nav: NavController, private githubUsers: GithubUsers) {
// Implementation commented out for brevity
}
// Search for user's from github
// Handle input event from search bar
search(searchTerm) {
let term = searchTerm.target.value;
// We will only perform the search if we have 3 or more characters
if (term.trim() == '' || term.trim().length < 3) {
// Get github users and assign to local user's variable
this.githubUsers
.load()
// Load original users in this case
.then(users => this.users = users)
} else {
// Get the searched users from github
this.githubUsers.searchUsers(term)
.then(users => this.users = users)
}
}
}
Two major changes here. We've added a private
key word to the githubUsers
in the cnstructor where it is injected as a parameter. This makes the
property to be available within the class and be accessible with the this
keyword. It's a nifty feature of TypeScript. You can read more about this in using typecript classes.Our search function is structured to only work when the search parameters are more than three. Go to
http://localhost:8100
, and try searching for a term, or a username you know.
Clicking any of the result should take you to that user's profile.# Build/Run the application.
Android
You need to have the android sdk set up. The installation instructions for your specific platform can be found here.Add android platform to your application
$ ionic platform add android
This adds a folder android within the platforms folder in your app and adds the neccesarry resources needed to build an android application.Build the android app
$ ionic build android
This builds the application, and puts the built apk in the platforms/android/build/outputs folder.Run the android app
$ ionic run android
This will run the app in either your default emulator, or a phone connected to your computer with usb debugging enabled.IOS
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
Add ios platform to your project. $ ionic platform add ios
This adds a folder ios within the platforms folder in your app and adds the necesarry resources needed to build an ios application.Build your app for ios
$ ionic build ios
This builds the application, and puts the build output in the platforms/ios/build/emulator folder.Then run the application in an ios simulator that comes installed with xCode
$ ionic run ios