app.core.scss
// http://ionicframework.com/docs/v2/theming/


// App Shared Imports
// --------------------------------------------------
// These are the imports which make up the design of this app.
// By default each design mode includes these shared imports.
// App Shared Sass variables belong in app.variables.scss.

@import "../pages/movie-list/movie-list";

@import "../pages/movie-info/movie-info";
 
These two lines are easy to understand. Application will use them to import movie-list page and movie-info page SCSS styles.
 
movie-list.html
<ion-header>
	<ion-navbar>
		<ion-title>
			Movie List
		</ion-title>
	</ion-navbar>
</ion-header>

<ion-content class="home" padding>
	<ion-item>
		<ion-input type="text" placeholder="Search a movie..." (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 component; top or bottom depending on a underlaying platform.
 
The other major component is a page content and it can be found inside an ion-content component. If you have a previous Ionic 1 experience, you’ll notice how this semantic is very similar to the old one.
 
Application will start with an input box we can use to enter a movie name:
 
<ion-item>
        <ion-input type="text" placeholder="Search a movie..." (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 movie-list class, you’ll see it in a next section.
 
When we enter a movie name, each time we add a new letter application will query a list of movie names matching entered value.
 
Query result will show inside an ion-item component.
 
<ion-item *ngFor="let movie of movies" (click)="itemTapped($event, movie)">

</ion-item>
 
Here we can see another new AngularJs 2 syntax:
 
*ngFor="let movie of movies"
 
ngFor is an AngularJs 2 replacement for ng-repeat. It will loop through movies array, and during each loop, an element will be added to movie variable. 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 mentined movie variable. You should already know this, itemTapped function is defined inside a movie-list class.
 
ngFor is also a new Angular 2 syntax, several versions ago it was ng-for; so be careful while googling Ionic 2 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 first part of a Master-Detail pattern.
 
movie-list.ts
import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';
import {MovieService} from '../services/MovieService';
import {MovieInfo} from '../movie-info/movie-info';

@Component({
    templateUrl: 'build/pages/movie-list/movie-list.html',
    providers: [MovieService]
})

export class MovieListPage {

    movies: Array<any>;

    constructor(private navController: 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) {
        this.navController.push(MovieInfo, {
            movie: movie
        });
    }
}
 
Again, import necessary components:
 
import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';
import {MovieService} from '../services/MovieService';
import {MovieInfo} from '../movie-info/movie-info';
 
MovieService is a 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, MovieInfo is a page we’re going to use to show selected movie details. It’s also the second part of Master-Detail pattern.
 
Connect this class with an appropriate HTML file:
 
@Component({
    templateUrl: 'build/pages/movie-list/movie-list.html',
    providers: [MovieService]
})
 
providers keyword is required so Angular can know how to create and inject an object of type MovieService. This is how AngularJS 2 handles dependency injection.
 
This code will not work without that keyword; you would receive this error:
 
EXCEPTION: No provider for MovieService! (MovieListPage -> MovieService)
 
This is how you can use MovieService service inside a movie-list class:
constructor(private navController: 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 service 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.navController.push(MovieInfo, {
		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 {Http} from '@angular/http';
import 'rxjs/add/operator/map';
 
export class MovieService {  
    static get parameters() {
        return [[Http]];
    }
 
    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 {Http} from '@angular/http';
import 'rxjs/add/operator/map';
 
movie-info.ts
import {Component} from '@angular/core';
import {NavController, NavParams} from 'ionic-angular';

@Component({
	templateUrl: 'build/pages/movie-info/movie-info.html'
})

export class MovieInfo {
	
	movie: {};	
	
	constructor(private navController: NavController, private navParams: NavParams) {
		this.movie = navParams.get('movie');
	}	
}
 
Here’s the second 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>
				<ion-item-content class="movie-title-data">
					<h1>{{movie.title}}</h1>
					<p>{{movie.release_date}}</p>
				</ion-item-content>
			</ion-item>

			<ion-item>
				<icon document item-left></icon>
				<h2>Overview</h2>
				<p class="item-description">{{movie.overview}}</p>
			</ion-item>
			<ion-item>
				<icon bookmark item-left></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
 
 

What to read next

IONIC 2 | Making REST HTTP Requests Like a Pro
 
 

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.

Blogs worth reading

If you're here looking for information related to the Ionic Framework, you will also like these blogs:






  • 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’