2015-12-24 1 views
14

Я пытаюсь играть с Угловая 2-бета и хочу работать с Http Компонент. Но есть серьезная проблема:Как эффективно использовать компонент Http в сервисе в угловой 2-й бета-версии?

Я прочитал this и я знаю, в угловых 2 (В отличие от Angular 1), Http компонент не сервис, который возвращает Promise. Он возвращает что-то под названием Observable. Мы знаем, что Компонент лучше не использовать Http напрямую. Эффективным способом является предоставление услуги, которая отвечает за потребление Http. Но как?! Если это после завершения запроса, верните обещание? (см. here)

Это вообще имеет значение ?!

+1

Вы ** можете ** использовать HTTP в качестве обещания, добавив '.toPromise()', за которым следует цепочка '.then()' вызовов. Тем не менее, наблюдаемые являются рекомендуемым подходом. –

+1

@EvanPlaice Да, я прочитал о них, и теперь я поклонник Observables :) –

+0

посмотрите на это http://stackoverflow.com/a/34758630/5043867 –

ответ

23

Возможно использование Angular 2 для реализации услуг. Они просто соответствуют инъекционным классам, как описано ниже. В этом случае этот класс может быть введен в другие элементы, такие как компоненты.

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; 
    } 
} 

Вы можете привнести в Http объект в нем (используя конструктор) при условии, указанный вами HTTP_PROVIDERS когда bootstraping основной компонент приложения:

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

bootstrap(AppComponent, [ 
    HTTP_PROVIDERS 
]); 

Данная услуга может быть затем введен в компонент, как описано ниже. Не забудьте указать его в списке компонента providers.

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; 
    } 
} 

Вы можете реализовать метод Усиливая Http объект в службе и вернуть Observable объект, соответствующий вашему запросу:

@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()); 
    } 
} 

Компонент может затем вызвать этот getCompanies метод и подписаться обратного вызова на объект Observable, который будет уведомляться, когда ответ будет обновлен для состояния компонента (аналогично тому, как вы делали с обещаниями в 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); 
    } 
} 

Редактировать

Как foxx предложил в своем комментарии, то async труба может быть также использован для неявно подписываются на наблюдаемом объекте. Вот как его использовать.Сначала обновить компонент поставить наблюдаемый объект в атрибуте вы хотите отобразить:

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

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

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

Используйте то асинхронные трубы в шаблоне:

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

Эта статья в двух частях могут дать более подробную информацию, как хорошо:

Надеется, что это помогает вам, Thierry

+7

Возможно, вы захотите использовать асинхронную трубу вместо ручной подписки , – foxx

+0

Большое спасибо @foox за ваш комментарий! Я обновил свой ответ, чтобы описать, как использовать асинхронный канал ;-) –

+0

Небольшой вопрос: вы импортировали 'HTTP_PROVIDERS' в bootstrap, но ввели« ROUTER_PROVIDERS ». это опечатка? –

6

Там нет необходимости конвертировать наблюдаемый возвращаемый ГЮТ в HTTP() метод в обещание. В большинстве случаев служба может просто вернуть наблюдаемый.

Если мы необходимо извлечь массив или примитивного типа (то есть строка, число, булевы) с сервера, мы можем упростить нашу логику контроллера с помощью возвращаемого наблюдаемого непосредственно в нашем шаблоне, с asyncPipe , Эта труба будет автоматически подписываться на наблюдаемую (она также работает с обещанием), и она вернет самое последнее значение, которое излучает наблюдаемое. Когда выдается новое значение, канал отмечает, что компонент должен быть проверен на изменения, поэтому представление автоматически обновится с новым значением.

Если мы необходимо извлечь объект с сервера, я не знаю ни одного способа использования asyncPipe, мы могли бы использовать асинхронную трубу, в сочетании с безопасным оператором навигации следующим образом:

{{(objectData$ | async)?.name}} 

Но это выглядит сложным, и нам нужно будет повторить это для каждого свойства объекта, которое мы хотели отобразить.

Вместо этого я предлагаю subscribe() наблюдаемому в компоненте и сохранить содержащийся объект в свойстве компонента. Затем мы используем safe navigation operator (?.) Или (как упоминается в комментарии @Evan Plaice в комментарии) NgIf в шаблоне. Если мы не используем безопасный навигационный оператор или NgIf, ошибка будет вызываться, когда шаблон сначала попытается выполнить рендеринг, потому что объект еще не заполнен значением.

Обратите внимание, что служба внизу всегда возвращает наблюдаемый для каждого метода get.

service.ts

import {Injectable} from 'angular2/core'; 
import {Http} from 'angular2/http'; 
import 'rxjs/add/operator/map'; // we need to import this now 

@Injectable() 
export class MyService { 
    constructor(private _http:Http) {} 
    getArrayDataObservable() { 
    return this._http.get('./data/array.json') 
     .map(data => data.json()); 
    } 
    getPrimitiveDataObservable() { 
    return this._http.get('./data/primitive.txt') 
     .map(data => data.text()); // note .text() here 
    } 
    getObjectDataObservable() { 
    return this._http.get('./data/object.json') 
     .map(data => data.json()); 
    } 
} 

app.ts

import {Component} from 'angular2/core'; 
import {MyService} from './my-service.service'; 
import {HTTP_PROVIDERS} from 'angular2/http'; 

@Component({ 
    selector: 'my-app', 
    providers: [HTTP_PROVIDERS, MyService], 
    template: ` 
    <div>array data using '| async': 
     <div *ngFor="#item of arrayData$ | async">{{item}}</div> 
    </div> 
    <div>primitive data using '| async': {{primitiveData$ | async}}</div> 
    <div>object data using ?.: {{objectData?.name}}</div> 
    <div *ngIf="objectData">object data using NgIf: {{objectData.name}}</div>` 
}) 
export class AppComponent { 
    constructor(private _myService:MyService) { console.clear(); } 
    ngOnInit() { 
    this.arrayData$  = this._myService.getArrayDataObservable(); 
    this.primitiveData$ = this._myService.getPrimitiveDataObservable(); 
    this._myService.getObjectDataObservable() 
     .subscribe(data => this.objectData = data); 
    } 
} 

Примечание: Я поставил "Наблюдаемая" в именах методов обслуживания – например, getArrayDataObervable() – только подчеркнуть, что метод возвращает Observable , Обычно вы не ставите «Observable» в названии.

данные/array.json

[ 1,2,3 ] 

данные/примитивными.JSON

Greetings SO friends! 

данные/object.json

{ "name": "Mark" } 

Выход:

array data using '| async': 
1 
2 
3 
primitive data using '| async': Greetings SO friends! 
object data using .?: Mark 
object data using NgIf: Mark 

Plunker


Один недостаток Usin g труба async заключается в том, что нет механизма для обработки ошибок сервера в компоненте. I answered another question, который объясняет, как поймать такие ошибки в компоненте, но в этом случае нам всегда нужно использовать subscribe().

+1

Полезной альтернативой оператору '?' (Elvis) является добавление '* ngIf' к разделу шаблона, в котором будут использоваться данные. Он обеспечивает более крупный уровень контроля, поэтому вам не нужно беспокоиться о том, чтобы разбрызгивать операторов elvis по всему шаблону или беспокоиться о том, как будет выглядеть шаблон, когда он отображается без данных. –

+0

@EvanPlaice, спасибо, я обновил ответ, чтобы включить ваше предложение. –

Смежные вопросы