home.html
<ion-header>
  <ion-navbar>
    <ion-title>Movie List</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
	<ion-item>
		<ion-label color="primary" stacked>Search movie database</ion-label>
		<ion-input type="text" (input)="searchMovieDB($event, searchKey)"></ion-input>
	</ion-item>

	<ion-list>	
		<ion-item *ngFor="let movie of movies" (click)="itemTapped($event, movie)">
			<ion-avatar item-left>
				<img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}"/>
			</ion-avatar>
			<h2>{{movie.original_title}}</h2>
			<p class="item-description">{{movie.overview}}</p>
		</ion-item>
	</ion-list>	
</ion-content>
 
This page is an application root page.
 
As you can see it has an ion-header section. Header location depends on an underlying platform (iOS-down or Android-up).
 
The second major part is a page content and it can be found inside an ion-content section. As you can see this semantic is very similar to the original Ionic 1 framework.
 
Our application will start with an input box we can use to enter a movie name:
 
<ion-item>
	<ion-label color="primary" stacked>Search movie database</ion-label>
	<ion-input type="text" (input)="searchMovieDB($event, searchKey)"></ion-input>
</ion-item>
 
Notice a new way of event handling in AngularJs:
 
(input)="searchMovieDB($event, searchKey)
 
A function searchMovieDB is part of a HomePage class, you’ll see it in a next section.
 
When we start writing movie name, after the third character, each time we add a new letter, an application will query a list of movie names matching entered value.
 
Result will be shown inside an ion-item component.
 
<ion-list>	
	<ion-item *ngFor="let movie of movies" (click)="itemTapped($event, movie)">
		.....
	</ion-item>
</ion-list>	
 
Here we can see another new Angular syntax:
 
*ngFor="let movie of movies"
 
ngFor is an Angular replacement for ng-repeat. It will loop through movies array, and during each loop, an element will be added to ion-list component. The let statement declares a block scope local variable, optionally initializing it to a value.
 
When we click/tap this ion-item element, it will trigger a click event calling a itemTapped function. One of the itemTapped function parameters is previously mentioned movie variable. You should already know this, itemTapped function is defined inside a HomePage class.
 
ngFor is also a brand new Angular, several iterations ago it was ng-for; so be careful while goggling Ionic examples.
 
ion-item holds a template that application will use to display query results:
 
<ion-avatar item-left>
	<img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}"/>
</ion-avatar>
<h2>{{movie.original_title}}</h2>
<p class="item-description">{{movie.overview}}</p>
 
The same templating system was used in a previous Ionic implementation.
 
Last but not least, this page is the Master part of the Master-Detail pattern.
 
home.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { MovieService } from '../../services/rest/movie-service';
import { MovieInfoPage } from '../movie-info/movie-info';

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

export class HomePage {

	movies: Array<any>;

	constructor(public navCtrl: NavController, private movieService: MovieService) {

	}

	searchMovieDB(event, key) {
		if(event.target.value.length > 2) {
			this.movieService.searchMovies(event.target.value).subscribe(
				data => {
					this.movies = data.results; 
					console.log(data);
				},
				err => {
					console.log(err);
				},
				() => console.log('Movie Search Complete')
			);
		}
	} 

	itemTapped(event, movie) {
		console.log(movie);  
		this.navCtrl.push(MovieInfoPage, {
			movie: movie
		});
	}
}
 
Again, import necessary components:
 
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { MovieService } from '../../services/rest/movie-service';
import { MovieInfoPage } from '../movie-info/movie-info';
 
MovieService is an injectable class holding REST call functions. I should also mention that this service doesn’t have an HTML component; we’ll talk more about it later.
 
On the other hand, MovieInfoPage is a page we’re going to use to show selected movie details. It’s also the Detail part of the Master-Detail pattern.
 
Connect this class with an appropriate HTML file:
 
@Component({
	selector: 'page-home',
	templateUrl: 'home.html'
})
 
This is how you can use MovieService service inside a movie-list class:
constructor(public navCtrl: NavController, private movieService: MovieService) {

}
 
Each time we enter a new letter into movie-list page search input, it will trigger function:
 
searchMovieDB(event, key) {
	if(event.target.value.length > 2) {
		this.movieService.searchMovies(event.target.value).subscribe(
			data => {
				this.movies = data.results; 
				console.log(data);
			},
			err => {
				console.log(err);
			},
			() => console.log('Movie Search Complete')
		);
	}
}
 
When we enter 3 or more characters a function will call a MovieService function searchMovies.
 
Take a special look at the subscribe function used after searchMovies. It is used to handle async REST query made inside a searchMovies function. This way, when REST call (inside a MovieService) finishes, the result will be added to this.movies variable. This may look strange but trust me, this solution is much easier than what we used to have in Angular 1.
 
itemTapped function is called when we click/tap list element:
 
itemTapped(event, movie) {
	console.log(movie);  
	this.navCtrl.push(MovieInfoPage, {
		movie: movie
	});
}
 
This is also a good and easy example of how Ionic 2 handles page navigation. You should no longer worry about routing. Simply use push function to change a page and add a new page to the navigation history or a pop function to remove a page from the navigation history.
 
The push function will accept two parameters. The first one is a page we’re trying to transition too and the second one is an object holding data we’re trying to pass to that page.
 
In this case, our application is sending a movie object holding all information about a selected movie.
 
MovieService.ts
import { Injectable } from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class MovieService {

    constructor(private http:Http) {

    }

    searchMovies(movieName) {
        var url = 'http://api.themoviedb.org/3/search/movie?query=&query=' + encodeURI(movieName) + '&api_key=5fbddf6b517048e25bc3ac1bbeafb919';
        var response = this.http.get(url).map(res => res.json());
        return response;
    }    
}
 
As you can see, this is a very simple service class. Again, we’re importing components necessary for the REST communication:
 
import { Injectable } from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';
 
movie-info.ts
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-movie-info',
  templateUrl: 'movie-info.html',
})
export class MovieInfoPage {

	movie: {};	

	constructor(public navCtrl: NavController, public navParams: NavParams) {
		this.movie = navParams.get('movie');
	}
}

 
Here’s the visible Detail part of Master-Detail pattern.
 
This page will display selected movie information and poster.
 
There’s only one thing worth mentioning in this class:
 
this.movie = navParams.get('movie'); 
 
This is how an application handles the data sent from the previous page via push function.
 
movie-info.html
<ion-header>
  <ion-navbar>
    <ion-title>Movie Info</ion-title>
  </ion-navbar>
</ion-header>


<ion-content class="home" padding>
	<div *ngIf="movie" class="selection">
		<ion-card>
			<ion-item>
				<ion-avatar item-left image-large>
					<img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}"/>
				</ion-avatar>
				<h1>{{movie.title}}</h1>
				<p>{{movie.release_date}}</p>
			</ion-item>

			<ion-item>
				<ion-icon name="document" item-left></ion-icon>
				<h2>Overview</h2>
				<p class="item-description">{{movie.overview}}</p>
			</ion-item>
			<ion-item>
				<ion-icon name="bookmark" item-left></ion-icon>
				<h2>Average Vote</h2>
				<p>{{movie.vote_average}}</p>
			</ion-item>
		</ion-card>
	</div>
</ion-content>
 
Finally here’s a movie-info.html page.
 
It’s just a template application is using to display selected movie information.
 

Deployment

 
Next step, build our application:
 
ionic build android
 
Be careful here, this step may break if you’re behind a firewall. The first execution will take a long time, so be patient.
 
Finally:
 
ionic run android -l -c -s
 
or if you want to test it in your browser:
 
ionic serve -l -c -s
 

Download The Code

 
Working GitHub repo link can be found below:
 
GitHub
 
 

Who Am I?

Between working as a senior Java developer in one of the largest insurance companies in the world and traveling, in my free time, I work as a professional mobile development adviser. I'm also a major jQuery Mobile supporter back at StackOverflow and a forum moderator at the official Ionic Framework forum.



  • Truc

    EXCEPTION: Cannot resolve all parameters for MovieService(?). Make sure they all have valid type or annotations.

  • Truc

    I got this error “EXCEPTION: Cannot resolve all parameters for MovieService(?). Make sure they all have valid type or annotations.”. Pls help

    • At what point have you received this error?

    • Oh I found a problem after Ionic 2.0.0-alpha.49 update. Apparently I must enforce metadata generation in my MovieService. I’ll update this article in next few minutes.

  • Basszer Billi

    Hi, I downloaded the source code from Git, but when I try run ionic serve, I’ve got errors.
    Emit skipped at State.emit, at transform, …
    It seems every error is from awesome-typescript-loader. How can I fix this?
    Thx

    • Basszer Billi

      oh, my bad, I had to install it.
      sorry 🙂

  • Piccaza

    Thank you so much. Took a long time to find out a tutorial on this topic. Ver very helpful.

    Also I have doubt regarding the `pop` , how it should written?

    In the above example when we come back to movies-list page from movie-info page, do we have to manually pop the movie-info page from nav?
    If so where do we have to write on what event. I am not getting idea on that.

  • Bla

    Just a quick question if you don’t mind, is the app made in Ionic2 able to be publish to app store yet? I know it’s in Beta, but I want to use it so badly..

    • Few people already done that while Ionic was still in the alpha so give it a go.

  • Gus Smith

    Using Ionic 2.0.0-beta.3
    Get error in service Unexpected token in line “constructor(@Inject(Http) http: Http)”

    Finally found another example that uses this:

    static get parameters() {
    return [[Http]];
    }

    constructor(http)

    Which works for me.

    • Thanks m8, I’ve updated article GitHub example, and tomorrow I’ll update this article.

  • Saifuddin

    app.html is not in the project in ionic beta version. please update your tutorial

    • Project has been updated to Ionic 2.0.0-beta.10 version.

  • selamet rahardjo

    hi, nice article, i have question can we access function that in @App class from @Page class? i mean i need some global function that will be available for @Page whether in class (.ts) or in layout (.html), thanks.

  • KingOfMyRoom

    Thank you for the tutorial. It’s really helpful to get a working example and get familiar with Ionic.

  • Abhinav

    mate! I’ve learnt a lot from your tuts.! Although, not directly related to this project, it would be awesome if you could just tell me how can we align an icon to the far right of a block/full width button. Or text to the far left. Can’t figure it out, for past 1 and a half hour. Thanks

  • Remzo

    I was lost quit quickly (newbie problems)

    It happened here:

    Somewhere below you’ll find a link to GitHub repo holding a working example (or you can copy past provided code).

    Can anyone please tell me:

    Where is “somewhere below”?
    Where is the “provided code”?

    Thanks!

  • Magiczny

    It seems to me that after the new update of Ionic you need to update the tutorial -> for instance when you start a new blank application there is no more app.html. Cheers;)

  • Vinicius Secco

    Hi! Great tutorial!

    There is a way to align multiple avatars?

    Thanks!

  • Phyo Zaw

    I downloaded the file from git and run it with ionic serve. However , I got only blank page. Is there anything missing I don’t know . Thanks

    • Salman

      I guess there is a folder (build) missing.

  • Dipak Mahapurkar

    Nice tutorial, I want to implement common tabs and sidemenu for all view, in ionic v1 this will i done, but in ionic v2 how i can implement such functionality. Please help me. Thanks you.

    • Slash

      I @dipakmahapurkar:disqus, do you found some solution? I’m not doing the same thing, but I tried to do something similar. I would have one menu and one header for all views. Some suggestions or examples?

  • Dwayne Patel

    ionic view not working

  • Mac S

    Getting Error while working with Git download:
    [WARN] Error occurred during command execution from a CLI plugin (@ionic/cli-plugin-cordova). Your plugins may be out of
    date.
    Error: Cannot find module ‘@ionic/app-scripts’

  • Javier Andrés Redolfi

    Hi!! nice tutorial, but I’m getting the following error after “ionic cordova run android –device –prod”:

    Error: Type MovieInfoPage in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/pages/movie-info/movie-info.ts is part of the declarations of 2 modules: AppModule in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/app/app.module.ts and MovieInfoPageModule in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/pages/movie-info/movie-info.module.ts! Please consider moving MovieInfoPage in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/pages/movie-info/movie-info.ts to a higher module that imports AppModule in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/app/app.module.ts and MovieInfoPageModule in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/pages/movie-info/movie-info.module.ts. You can also create a new NgModule that exports and includes MovieInfoPage in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/pages/movie-info/movie-info.ts then import that NgModule in AppModule in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/app/app.module.ts and MovieInfoPageModule in /home/jaarac/borrar/ionic/IonicFirstApplicationExample/src/pages/movie-info/movie-info.module.ts.
    at Error (native)
    at syntaxError (/home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:1729:34)
    at CompileMetadataResolver._addTypeToModule (/home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:15733:31)
    at /home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:15621:27
    at Array.forEach (native)
    at CompileMetadataResolver.getNgModuleMetadata (/home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:15612:54)
    at addNgModule (/home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:24408:58)
    at /home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:24419:14
    at Array.forEach (native)
    at _createNgModules (/home/jaarac/borrar/ionic/IonicFirstApplicationExample/node_modules/@angular/compiler/bundles/compiler.umd.js:24418:26)

    • Hi Javier. Tell me few things please. Is this code I provided and without any changes on your side? And if yes did you pull my changes from the GitHub or have you copied code provided in the article?