soroush gholamzadeh soroush gholamzadeh - 7 months ago 42
Javascript Question

How to Consume Http Component efficiently in a service in angular 2 beta?

I'm trying to play with Angular 2-beta and I want to work with Http component. But there is a serious problem here:

I read this and
I know in Angular 2(Unlike Angular 1), Http component is not a service that returns a Promise. It returns something called Observable. We know that a Component is better not to use Http directly. Efficient way is to make a service that is responsible to consume Http. But how?! Should this after completing a request, return a promise? (look at here)

Does it make sense at all?!

Answer

It's possible with Angular 2 to implement services. They simply correspond to injectable classes as described below. In this case this class can be injected into other elements like components.

import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
import 'rxjs/add/operator/map';

@Injectable()
export class CompanyService {
  constructor(http:Http) {
    this.http = http;
  }
}

You can inject an Http object in it (using its constructor) at the condition you specified HTTP_PROVIDERS when bootstraping the main component of your application:

import {bootstrap} from 'angular2/platform/browser'
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component'

bootstrap(AppComponent, [
  HTTP_PROVIDERS
]);

This service can be then injected into a component, as described below. Don't forget to specify it within the providers list of the component.

import { Component, View, Inject } from 'angular2/core';
import { CompanyService } from './company-service';

@Component({
  selector: 'company-list',
  providers: [ CompanyService ],
  template: `
    (...)  `
})

export class CompanyList {
  constructor(private service: CompanyService) {
    this.service = service;
  }
}

You can then implement a method leveraging the Http object in your service and return the Observable object corresponding to your request:

@Injectable()
export class CompanyService {
  constructor(http:Http) {
    this.http = http;
  }

  getCompanies() {
    return this.http.get('https://angular2.apispark.net/v1/companies/')
                  .map(res => res.json());
  }
}

The component can then call this getCompanies method and subscribe a callback on the Observable object to be notify when the response is there to update the state of the component (in the same way you did with promises in Angular1):

export class CompanyList implements OnInit {
  public companies: Company[];

  constructor(private service: CompanyService) {
    this.service = service;
  }

  ngOnInit() {
    this.service.getCompanies().subscribe(
      data => this.companies = data);
  }
}

Edit

As foxx suggested in his comment, the async pipe could be also used to implicitly subscribe on the observable object. Here is the way to use it. First update your component to put the observable object in the attribute you want to display:

export class CompanyList implements OnInit {
  public companies: Company[];

  constructor(private service: CompanyService) {
    this.service = service;
  }

  ngOnInit() {
    this.companies = this.service.getCompanies();
  }
}

Use then the async pipe in your template:

@Component({
  selector: 'company-list',
  providers: [ CompanyService ],
  template: `
    <ul>
      <li *ngFor="#company of companies | async">{{company.name}}</li>
    </ul>
  `
})
export class CompanyList implements OnInit {
  (...)
}

This article in two parts could give more details as well:

Hope it helps you, Thierry