Ionic Framework | Master Detail Pattern Overview

Written by on April 9, 2015

Ionic Framework | Master Detail Pattern Overview

This application will have two distinct pages, first one (Master) will act as a search page (list.html) while a second one (Detail) will act as a more details page (view.html). Ionic routing system will dynamically load child pages depending on application navigation system (we will discuss this later). Both application pages (child pages) require a distinct controller:

demoApp.controller('ListCtrl', function($scope, $http, Movies) {
demoApp.controller('ViewCtrl', function($scope, $http, $stateParams, Movies) {

…Ctrl under controller name is an Angular convention. but you can give it any name. For better future readability stick to this convention. Another important thing to remember is $scope. This is Angular model, it’s just a javascript object. Each $scope will hold associated page data. As you can see you don’t need to call set or get functions if you want to change something inside a $scope (like in Backbone case), just access it like any other JavaScript object:

$scope.movies = movies;

Our first HTML page (list.html) contains only two page structures (elements), our search input and an empty list holder template. Our second page (view.html) has only one card template. This templete system is made to mimic HandlebarsJS template engine (or older {{mustache}} engine). For example this is a list holder template we are using in our example:

<div class="list">
 
  <a ng-repeat="movie in movies" href="#/movie/{{movie.id}}" class="item item-thumbnail-left">
    <img ng-src="http://d3gtl9l2a4fn1j.cloudfront.net/t/p/w185{{movie.poster_path}}" onerror="this.src = 'https://www.ginesisnatural.com/images/no_image.jpg';">
    <h2>{{movie.original_title}}</h2>
    <h4>{{movie.release_date}}</h4>
  </a>
 
</div>

{{movie.original_title}} represents object movie -> parameter original_title.

Application we’re building is a perfect example of a master-detail pattern. First page will hold a list of movies while another one will hold specific information about selected movie. It can’t get easier than that.

Now let’s talk about how this application works. First we need to write something into our search input, it looks like this:

<input type="search" placeholder="Search" ng-model="movie.name" ng-change="searchMovieDB()">

Because this input has an AngularJS attribute ng-model=”movie.name” everything we write in it will be bound to $scope object movie:

  $scope.movie = {
    name: ''
  }

Advanced note: this is where Ionic frameworks differs a bit from the vanilla AngularJS. In AngularJS case we could have used primitive variable instead of an object. Unfortunately, thanks to some Ionic framework handlings, everything found inside a tag (directive) will be part of a child scope and one of the ways for it to access main scope is for us to bind it to a main scope object (not primitive variable, it will not work in this case), in our case it is $scope.movie = {....

Another important thing about this input box is, each time we change something it will trigger change event bound to this input box (ng-change=”searchMovieDB()”). This event will trigger function searchMovieDB which is part of a List controller (ListCtrl):

$scope.searchMovieDB = function() {

This is where things get a little bit complicated. This function will call another function which is part of a factory service called Movies. This :

Movies.list($scope.movie.name, function(movies) {

will call this:

list: getData,

which is a part of a Movies factory service. AngularJS factory lets you create a service that you can use with AngularJS dependency injection. This is recommended way of exposing data from the server to the Angular views. In a few words, dependency injection is a software design pattern in which an object is given its dependencies, rather than the object creating them itself. It is about removing the hard-coded dependencies and making it possible to change them whenever needed. Don’t worry if you don’t understand a word I’m saying, you will learn it sooner or later.

Movies factory function list will accept two parameters, a first one is movie name and second one is an anonymous callback function we will use to acquire a list of searched movies. Function list will call another function getData:

function getData(moviename, callback) {

This function will in turn initiate a REST call to moviedb service, acquire a movie list and set it to the original scope using passed callback function. It will set original scope object $scope.movies, which will in turn trigger list template population:

<a ng-repeat="movie in movies" href="#/movie/{{movie.id}}" class="item item-thumbnail-left">
    <img ng-src="http://d3gtl9l2a4fn1j.cloudfront.net/t/p/w185{{movie.poster_path}}" onerror="this.src = 'https://www.ginesisnatural.com/images/no_image.jpg';">
    <h2>{{movie.original_title}}</h2>
    <h4>{{movie.release_date}}</h4>
</a>

Attribute ng-repeat=”movie in movies” will loop through the object movies and build page content using acquired JSON data and list template.

Here’s where we come to the next big thing. I already told you we will have two pages (two controllers). When we click on a listview element we want to go to the another page where we will be able to see additional movie details. Relationships between pages are set using routing:

nameApp.config(function($stateProvider, $urlRouterProvider) {
 
  $stateProvider
    .state('list', {
      url: '/',
      templateUrl: 'list.html',
      controller: 'ListCtrl'
    })
    .state('view', {
      url: '/movie/:movieid',
      templateUrl: 'view.html',
      controller: 'ViewCtrl'
    });
 
  $urlRouterProvider.otherwise("/");
 
});

AngularJS routes enable you to show different content depending on what route is chosen. A route is specified in the URL after the # sign. In our case, depending on a link href attribute application will show you either list page or view page. Each page has its own controller, for example, list page has ListCtrl controller and view page has ViewCtrl controller.

Nothing of this would not work without these Ionic directives (set inside of an index.html):

<ion-nav-view></ion-nav-view>

As a user navigates throughout your app, Ionic is able to keep track of their navigation history. By knowing their history, transitions between views correctly enter and exit using the platform’s transition style. This is what this navigation system serves for.

When application transitions to the view page it will gather specific movie data using object/parameter $stateParams.movieid we passed using application routing system:

url: '/movie/:movieid',

Acquired data will generate another page content, again using prepared template.

<div class="list card">

	<div class="item item-avatar">
	  <img src="http://files.softicons.com/download/object-icons/movies-icons-by-pinchodesigns/png/32x32/Movie.png">
	  <h2>{{movie.original_title}}</h2>
	  <p>{{movie.release_date}}</p>
	</div>

	<div class="item item-image">
	  <img ng-src="http://d3gtl9l2a4fn1j.cloudfront.net/t/p/w185{{movie.poster_path}}" width="200px" />
	</div>

	<a class="item" href="#">
		Average Vote: <strong>{{movie.vote_average}}</strong> (Votes: {{movie.vote_count}})
	</a>

</div>

And that’s everything you need to know about this application. I hope this example will help you as much as possible. If you have additional questions please leave them in a comment section below.

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.



Categories

5 thoughts on “Ionic Framework | Master Detail Pattern Overview”

  1. The topic should have been simpler. The main intention is to explain master detail pattern and adding a database discussion to it only makes it complicated. Making the data local will give a complete picture.

    Say, we are working on local data and I have a list of 20 movies added to $scope.movies object with a variable called id, when I want to filter it on id, I get both id’s 1, 11, 12, 13…19. How can I filter the exact match?

    • Tho point of this article is to show a real working example. It doesn’t matter where the source is. 95 % of the code is going to be the same. Plus why should I spend my time building a localstorage example when I can use already existing data source.

  2. Cool beans – this is great fully working example of “master/detail” using Ionic! The concise explanations are very helpful – I’m sure there’s a lot of detail left for one to discover/learn (in Ionic/Angular) but for the purposes of the example, it keeps things compact and not go off on multiple concepts (but it’s understood that there are). Kudos and thank you.

  3. sir i need your help ,im using your above code ,i followed all instruction described above but when run the code its coming blank for me …plz help me

Leave a Reply to Karthik Cancel reply