Я использую forkJoin
чтобы превратить несколько наблюдаемых в один, который затем forkJoin
чтобы преобразовать в некоторую модель представления, которую я использую для своего представления в моем компоненте.
Моя модель выглядит следующим образом:
export interface MyModel {
itemOne: Observable<ItemOne[]>;
itemTwo: Observable<ItemTwo[]>;
itemThree: Observable<ItemThree[]>;
}
Мой forkJoin
выглядит так:
this._subscriptions.push(this.myService.getData()
.flatMap(data => Observable.forkJoin(data
.map(data => {
let myModel: MyModel = {
itemOne: this.myService.getSomeData(),
itemTwo: this.myService.getSomeData(),
itemThree: this.myService.getSomeData()
};
return Observable.forkJoin(Observable.from([myModel]));
}))).subscribe(details => {
details.map(this.toMyModelViewModel.bind(this));
}));
Теперь, в моем методе toMyModelViewModel
, я хотел бы выбрать каждое значение из этих Observables и задавался вопросом, как я мог бы это сделать?
toMyModelViewModel(value: MyModel): any {
return {
itemOne: value.itemOne,
itemTwo: value.itemTwo,
itemThree: value.itemThree
};
}
Должен ли я подписаться на каждое значение, чтобы получить текущее значение, или есть другой, возможный лучший/более чистый способ сделать это? В конечном счете, я хотел бы иметь массив объектов MyModel, поэтому мне не нужно беспокоиться об использовании data | async
data | async
на мой взгляд.
Спасибо
Вы можете преобразовать массив наблюдаемых в наблюдаемый массив, используя любой метод, который вам нравится - тот, который Миллер показывает в своем ответе, будет работать. Мне лично нравится трюк combineLatest
(цитируя от redent84 ответ на этот вопрос: как создать наблюдаемый массив из массива наблюдаемых?).
let arrayOfObservables: [Observable<E>] = ...
let wholeSequence: Observable<[E]> = Observable.combineLatest(arrayOfObservables)
Теперь, для вашего реального вопроса:
Должен ли я подписаться на каждое значение, чтобы получить текущее значение, или есть другой, возможный лучший/более чистый способ сделать это? В конечном счете, я хотел бы иметь массив объектов MyModel, поэтому мне не нужно беспокоиться об использовании данных | async, на мой взгляд.
К сожалению, единственный способ получить Array<any>
из Observable<Array<any>>
- это подписаться на наблюдаемое и сохранить внутреннее значение в массиве, определенном в другом месте, или (если вы используете Angular как вы), чтобы использовать async
трубу.
Вы можете думать об этом так: однажды Observable
, всегда Observable
. Если значение обернуто в Observable
, вы не сможете его получить. Наиболее близким к этому поведению может быть использование BehaviorSubject
с методом getValue
, но это определенно не вариант для Observables. Это хорошо, потому что это мешает вам использовать асинхронное значение "синхронно" в вашей программе.
Мне также кажется, что я должен упомянуть, что async
труба - действительно полезная утилита и должна быть предпочтительной для ручного подписания в целом. Когда вы вручную создаете подписку в своем классе компонентов, вам нужно будет запомнить эту подписку и очистить ее в ngOnDestroy
жизненного цикла ngOnDestroy
. async
трубка великолепна, потому что она выполняет всю эту очистку для вас. Кроме того, вы можете использовать его с безопасным навигационным оператором для обработки значений, которые могут быть неопределенными.
<ul>
<li *ngFor="let obj of (possiblyUndefined$ | async)?.objects">
{{ obj.title }}
</li>
</ul>
Этот код будет намного сложнее, если вы написали все это в своем классе компонента.
Подвести итоги:
1) Вы можете использовать Observable.combineLatest(arrayOfObservables)
чтобы подавить ваш массив наблюдаемых в наблюдаемый массив.
2) Вы не можете получить массив "из" наблюдаемого. Вы должны либо подписаться на это наблюдаемое, либо использовать async
канал.
Из быстрого сканирования вашего кода кажется, что у вас есть начальный api-вызов (this.myService.getData()
), из которого вы this.myService.getData()
свой результат, но этот результат основан на объединении результатов нескольких вызовов api (this.myService.getSomeData()
).
Я чувствую, что вам нужен интерфейс MyModel
чтобы не иметь Observables:
export interface MyModel {
itemOne: ItemOne[];
itemTwo: ItemTwo[];
itemThree: ItemThree[];
}
... toMyViewModel
- это заводский метод:
function toMyModelViewModel(itemOne: any, itemTwo: any, itemThree: any): MyModel {
return {
itemOne: itemOne as ItemOne[],
itemTwo: itemTwo as ItemTwo[],
itemThree: itemThree as ItemThree[]
} as MyModel;
}
... тогда вы будете использовать switchMap/forkJoin следующим образом:
this.myService.getData().switchMap(data => {
return Observable.forkJoin(
this.myService.getSomeData(),
this.myService.getSomeData(),
this.myService.getSomeData(),
toMyModelViewModel
}).subscribe(...);