ОБНОВЛЕНИЕ: 24.09.16 Angular 2.0 Stable
Этот вопрос по-прежнему вызывает много трафика, поэтому я хотел его обновить. Из-за безумия изменений от кандидатов Alpha, Beta и 7 RC я перестал обновлять свои ответы SO, пока они не стали стабильными.
Это идеальный случай для использования Subjects и ReplaySubjects.
Я лично предпочитаю использовать, ReplaySubject(1)
поскольку он позволяет передавать последнее сохраненное значение, когда новые подписчики подключаются, даже когда поздно:
let project = new ReplaySubject(1);
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject
project.next(result));
//add delayed subscription AFTER loaded
setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});
//Output
//Subscription Streaming: 1234
//*After load and delay*
//Delayed Stream: 1234
Поэтому, даже если я подключаюсь поздно или мне нужно загрузить позже, я всегда могу получить последний звонок и не беспокоиться о пропущенном обратном вызове.
Это также позволяет использовать тот же поток для нажатия на:
project.next(5678);
//output
//Subscription Streaming: 5678
Но что, если вы на 100% уверены, что вам нужно позвонить только один раз? Оставлять открытые темы и наблюдаемые нехорошо, но всегда есть такое «Что, если?»
Вот где на помощь приходит AsyncSubject .
let project = new AsyncSubject();
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result),
err => console.log(err),
() => console.log('Completed'));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject and complete
project.next(result));
project.complete();
//add a subscription even though completed
setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});
//Output
//Subscription Streaming: 1234
//Completed
//*After delay and completed*
//Delayed Sub: 1234
Потрясающие! Несмотря на то, что мы закрыли тему, он все равно ответил последней загруженной информацией.
Другое дело, как мы подписались на этот http-вызов и обработали ответ. Карта отлично подходит для обработки ответа.
public call = http.get(whatever).map(res => res.json())
Но что, если нам нужно вложить эти вызовы? Да, вы можете использовать предметы со специальной функцией:
getThing() {
resultSubject = new ReplaySubject(1);
http.get('path').subscribe(result1 => {
http.get('other/path/' + result1).get.subscribe(response2 => {
http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3))
})
})
return resultSubject;
}
var myThing = getThing();
Но это много и означает, что для этого вам нужна функция. Введите FlatMap :
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Милая, var
это наблюдаемая, которая получает данные из последнего HTTP-вызова.
Хорошо, это здорово, но мне нужен сервис angular2!
Понял тебя:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ReplaySubject } from 'rxjs';
@Injectable()
export class ProjectService {
public activeProject:ReplaySubject<any> = new ReplaySubject(1);
constructor(private http: Http) {}
//load the project
public load(projectId) {
console.log('Loading Project:' + projectId, Date.now());
this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res));
return this.activeProject;
}
}
//component
@Component({
selector: 'nav',
template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>`
})
export class navComponent implements OnInit {
public project:any;
constructor(private projectService:ProjectService) {}
ngOnInit() {
this.projectService.activeProject.subscribe(active => this.project = active);
}
public load(projectId:string) {
this.projectService.load(projectId);
}
}
Я большой поклонник наблюдателей и наблюдаемых, поэтому надеюсь, что это обновление поможет!
Оригинальный ответ
Я думаю , что это использование случай использования Observable Subject или в .Angular2
EventEmitter
В своем сервисе вы создаете объект, EventEmitter
который позволяет вам вводить в него значения. В Alpha 45 вам нужно преобразовать его с помощью toRx()
, но я знаю, что они работали над тем, чтобы избавиться от этого, поэтому в Alpha 46 вы можете просто вернуть EvenEmitter
.
class EventService {
_emitter: EventEmitter = new EventEmitter();
rxEmitter: any;
constructor() {
this.rxEmitter = this._emitter.toRx();
}
doSomething(data){
this.rxEmitter.next(data);
}
}
У этого способа есть сингл, EventEmitter
который теперь могут использовать ваши различные сервисные функции.
Если вы хотите вернуть наблюдаемое непосредственно из вызова, вы можете сделать что-то вроде этого:
myHttpCall(path) {
return Observable.create(observer => {
http.get(path).map(res => res.json()).subscribe((result) => {
//do something with result.
var newResultArray = mySpecialArrayFunction(result);
observer.next(newResultArray);
//call complete if you want to close this stream (like a promise)
observer.complete();
});
});
}
Это позволит вам сделать это в компоненте:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
И поиграйте с результатами звонка в ваш сервис.
Мне нравится создавать EventEmitter
поток самостоятельно, на случай, если мне нужно получить к нему доступ из других компонентов, но я мог видеть оба способа работы ...
Вот плункер, который показывает базовую службу с эмиттером событий: Plunkr
EventEmitter
для чего угодно, но@Output()
не рекомендуется. См. Также stackoverflow.com/questions/34376854/…Это пример из документации Angular2 о том, как вы можете создавать и использовать свои собственные Observables:
Сервис
Компонент
Полный рабочий пример можно найти здесь: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
источник
Я хотел бы добавить, что если создаваемый объект статичен и не проходит через http, можно сделать что-то подобное:
Изменить: для отображения Angular 7.xx необходимо использовать pipe (), как описано здесь ( https://stackoverflow.com/a/54085359/986160 ):
из ответа на мой вопрос о наблюдателях и статических данных: https://stackoverflow.com/a/35219772/986160
источник
Я немного опоздал на вечеринку, но я думаю, что мой подход имеет то преимущество, что в нем не используются EventEmitters и Subjects.
Итак, вот мой подход. Мы не можем уйти от subscribe () и не хотим этого. В этом ключе наша служба вернет сообщение
Observable<T>
с наблюдателем, у которого есть наш драгоценный груз. От вызывающей стороны мы инициализируем переменнуюObservable<T>
, и она получит файл службыObservable<T>
. Далее мы подпишемся на этот объект. Наконец-то вы получили свою "Т"! из вашей службы.Во-первых, наши люди обслуживают, а у вас параметры не передаются, это более реалистично:
Хорошо, как видите, мы возвращаем объект
Observable
типа "люди". В подписи метода даже так написано! Мы_people
вставляем объект в нашего наблюдателя. Далее мы получим доступ к этому типу из вызывающего объекта в компоненте!В Компоненте:
Мы инициализируем наш
_peopleObservable
, возвращая егоObservable<people>
из нашегоPeopleService
. Затем мы подписываемся на это свойство. Наконец, мы устанавливаемthis.people
нашpeople
ответ data ( ).Подобная архитектура службы имеет одно важное преимущество перед обычным шаблоном service: map (...) и component: «subscribe (...)». В реальном мире нам нужно сопоставить json с нашими свойствами в нашем классе, и иногда мы делаем там что-то особенное. Таким образом, это отображение может происходить в нашем сервисе. И, как правило, поскольку вызов нашей службы будет использоваться не один раз, а, вероятно, в других местах нашего кода, нам снова не нужно выполнять это сопоставление в каком-то компоненте. Более того, что, если мы добавим людям новое поле? ....
источник
В файле service.ts -
а. импорт 'of' из наблюдаемого / из
b. создать список json
c. вернуть объект json с помощью Observable.of ()
Ex. -
В компоненте, где мы вызываем функцию get службы -
источник
Обратите внимание, что вы используете Observable # map для преобразования необработанного
Response
объекта, который излучает ваш базовый Observable, в проанализированное представление ответа JSON.Если я вас правильно понял, вы
map
снова захотите . Но на этот раз преобразование этого необработанного JSON в экземпляры вашегоModel
. Итак, вы бы сделали что-то вроде:Итак, вы начали с Observable, который испускает
Response
объект, превратили его в наблюдаемый, который испускает объект проанализированного JSON этого ответа, а затем превратили его в еще один наблюдаемый объект, который превратил этот необработанный JSON в массив ваших моделей.источник