Angular 2 and Ionic 2 Data Services
Part 1: Promises and Observables

In this post I continue to improve the IonicRealty sample application I shared last week. In particular, I revisit the data access part of the application. The initial version of the application used simple mock services that weren’t really built the “Angular way”. In this article, I share two approaches to build Angular-style mock services. In part 2, I’ll share a REST implementation of the same services.

Mock services are used for prototypes, during early or offline development, or to test components at a granular level. A key design principle is to make your mock services expose the exact same API as the services they substitute. For example, if you are building a service that stands in for a REST service, it should expose the same asynchronous API as that REST service. API consistency makes the services interchangeable: you can easily switch back and forth between the mock service and the REST service without having to change the calls to the service throughout the application.

Using Promises

Promises are the de-facto standard for asynchronous processing in JavaScript. Let’s take a look at the Property service of the IonicRealty app implemented with Promises (showing only one “find” method for brevity):

property-service.js:

import {Injectable} from 'angular2/core';
import {PROPERTIES} from './mock-properties';

@Injectable()
export class PropertyService {

    findAll() {
        return new Promise((resolve, reject) => resolve(PROPERTIES));
    }

}

To mimic a traditional REST service method, findAll() creates an ES2015 Promise that it resolves immediately. Pages and components can then call findAll() and handle the result in the promise’s then() function as shown here in the ngOnInit function of the PropertyListPage:

property-list.js:

import {OnInit} from 'angular2/core';
import {Page, NavController, NavParams} from 'ionic/ionic';
import {PropertyService} from '../../services/property-service';

@Page({
    templateUrl: 'build/pages/property-list/property-list.html'
})
export class PropertyListPage {

    constructor(nav:NavController, navParams:NavParams, propertyService:PropertyService) {
        this.nav = nav;
        this.propertyService = propertyService;
        this.selectedItem = navParams.get('item');
    }

    ngOnInit() {
        this.propertyService.findAll().then(data => this.properties = data);
    }

}

Using Observables

The problem with the previous implementation is that the Angular 2 http object methods (get, post, put, etc.) don’t return Promises: they return Observables from the RxJS library. If the mock service methods return Promises and the REST service methods return Observables, the two services won’t be interchangeable. There are two options to address this issue:

  1. Standardize on a Promise-based API: In the REST service implementation, convert the Observables returned by the http methods to Promises. This can be done using the Observable.toPromise() function.
  2. Standardize on an Observable-based API: In the Mock service implementation, return dummy Observables instead of dummy Promises.

As an example of the second approach, here is a modified version of the Mock Property service using an Observable-based API:

property-service.js:

import {Injectable} from 'angular2/core';
import {PROPERTIES} from './mock-properties';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class PropertyService {

    findAll() {

        return Observable.create(observer => {
            observer.next(PROPERTIES);
            observer.complete();
        });

    }

}

Pages can then call findAll() and subscribe to process the result:

property-list.js:

import {OnInit} from 'angular2/core';
import {Page, NavController, NavParams} from 'ionic/ionic';
import {PropertyService} from '../../services/property-service';

@Page({
    templateUrl: 'build/pages/property-list/property-list.html'
})
export class PropertyListPage {

    constructor(nav:NavController, navParams:NavParams, propertyService:PropertyService) {
        this.nav = nav;
        this.propertyService = propertyService;
        this.selectedItem = navParams.get('item');
    }

    ngOnInit() {
        this.propertyService.findAll().subscribe(data => this.properties = data);
    }

}

Providers

For Angular to be able to inject PropertyService in PropertyListPage, you need to add it to the list of providers. You could do it at the page level:

@Page({
    templateUrl: 'build/pages/property-list/property-list.html',
    providers: [PropertyService]
})

But since the PropertyService is used in many pages throughout the application, I declared it at the App level (in app.js):

import {PropertyService} from './services/property-service';

@App({
    templateUrl: 'build/app.html',
    config: {},
    providers: [PropertyService]
})

Source Code

The modified source code and installation instructions for the application are available in this repository on GitHub.

Feedback

Since Angular 2 is still in beta and a lot of this is new to Angular 2, I’m interested in your feedback. How do you build your own mock and actual services? What strategy have you developed to make them easily interchangeable?

  • Pingback: Angular 2 and Ionic 2 Data ServicesPart 2: Using REST Services | Christophe Coenraets()

  • Nice explanation on Angular 2 . I used to work in this on my upcoming project

  • Indeed coding is one of the toughest thing i ever find but nice blog

  • Pingback: Building Customer-Facing Mobile Apps with Angular 2, Ionic 2, and Salesforce | Christophe Coenraets()

  • i ever find but nice blog

  • I found lots of interesting information here.Great work
    Thanks for the share loved reading the article, please do share more like this wiht us .

  • i ever find but nice blog

  • Nice explanation on Angular 2 . I used to work in this on my upcoming project

  • Very interesting blog. Alot of blogs I see these days don’t really provide anything that I’m interested in, but I’m most definately interested in this one. Just thought that I would post and let you know

  • Piccaza

    Hi Christophe,

    I am getting following error while trying the above code scenario in my app:
    Cannot read property ‘subscribe’ of undefined

  • I just want to say thanks for your wonderful post, it is contain a lot of knowledge and information that i needed right now.
    You really help me out my friend, thanks!

  • Good blog post. I want to thank you for interesting and helpful information and I like your point of view. Thank you!- I love to read this type of material Good and attractive information I take from it..
    Thank you for posting such a good article.

  • In latest ionic 2 cli, all serviecs goes to app/providers folder by default

    Thanks for post ..

  • With observables, how to call something like finally on promise, to always run function both on success or error?

    I’ve try to catch on () => {} but didnt work

    Thanks

    • twicejr

      .subscribe(
      data => {
      console.log(‘toasted’, toast);
      },
      error => {
      console.log(‘error’, error);
      },
      () => {
      //complete
      }
      );

  • This situation, in actuality, makes Bengaluru a speculator’s heaven. The city brings to the table unparalleled pads, cabins, column houses, manors, penthouses, and so on to purchasers giving the Bengaluru extends an edge over others. The accessible property in Bengaluru relating to the private section can adequately be grouped into three general classes moderate lodging, mid-pay lodging and extravagance lodging.
    Real Estate Trends in bengaluru

  • John

    Very useful information on this post.
    Thank you for sharing this information with us all.
    http://instafollowersjunction.com

  • Thanks for sharing the information. It is very useful for my future. keep sharing. Can you play more games at :
    swords and souls | strike force kitty 2 | swords and souls game | strikeforce kitty 2

  • I’m interested in your part 2!

css.php