angular - När ska man använda RxJS Observable<Object[]> och Observable<Object>?
Med Angular 6 definierade jag mina tjänster baserat på hero-appen. Om en metod ska returnera flera värden returnerar jag alltid en Observable<A[]> och om jag förväntar mig en enskild retur, till exempel om metoden är getById, returnerar jag Observable<A>.
Problemet är att idag ville jag göra en groupBy() på en av de returnerade arrayen av värden och alla exempel jag kunde hitta använder bara Observable<A> istället för Observable<A[]>, som detta exempel. Dessutom, om man tittar på svaren här (jag provade det, detta fungerar bara på ~Observable<A>) och RxJS-introduktionen (Observable: represents the idea of an invokable collection of future values or events.), verkar det som att jag borde ha använt Observable<A> för samlingar som servern returnerar, men vad använder jag då för enstaka värden?
Exempel på tjänster:
all(): Observable<T[]> {
return this.httpClient.get<T[]>(this.urls().allURL());
}
paginate(pageRequest: any): Observable<Page<T>> {
return this.httpClient.post<Page<T>>(this.urls().paginateURL(), pageRequest);
}
findOneById(id: number): Observable<T> {
return this.httpClient.get<T>(this.urls().byIdURL(id));
}
Uppdatering :
Jag gjorde ett exempelprojekt. Jag kan arbeta med array-observables på det här sättet, men då behöver jag alltid en mergeMap. Jag förstår att om jag använder Observable<A[]>, kommer jag få alla värden på en gång, eftersom de finns i en array, men om jag använder Observable<A> får jag dem en i taget, vilket är anledningen till att jag till exempel inte kan använda det i en *ngFor (förväntar sig en array). Frågan är om jag alltid ska använda A[] när servern synkront returnerar en samling och A om jag arbetar med asynkron data, eller om jag även behöver beakta andra scenarier.
import { Component, OnInit } from '@angular/core';
import { Observable, from, of, GroupedObservable } from 'rxjs';
import { distinct, map, mergeMap, toArray, groupBy } from 'rxjs/operators';
export class ModelA {
id: number;
name: string;
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular';
models: Observable<ModelA[]>;
distinctModels: Observable<ModelA[]>;
groupedModels: Observable<ModelA[][]>;
ngOnInit() {
this.loadData();
}
loadData(): void {
this.models = of([
{id: 1, name: 'Name A'},
{id: 2, name: 'Name A'},
{id: 3, name: 'Name B'},
{id: 4, name: 'Name C'}
]);
this.distinctModels = this.models
.pipe(
mergeMap(models => models),
distinct(m => m.name),
toArray()
);
this.distinctModels.subscribe( m => console.log(m));
this.groupedModels = this.models
.pipe(
mergeMap(models =>models),
groupBy(model => model.name),
mergeMap(toArray()),
toArray()
);
this.groupedModels.subscribe( m => console.log(m));
}
}
Svar #1
Jag är inte säker på vad du vill. Om det är en Grupp bara Observable< any[][] >
export class AppComponent implements OnInit {
people: any[] = [
{ name: 'Sue', age: 25 },
{ name: 'Joe', age: 30 },
{ name: 'Frank', age: 25 },
{ name: 'Sarah', age: 35 }
];
result:any[][];
ngOnInit()
{
this.myObservable().subscribe(res=>{
this.result=res;
})
}
myObservable():Observable<any[][]>
{
return from(this.people).pipe(
groupBy((person:any)=>person.age),
mergeMap(group=>group.pipe(toArray())),
toArray());
}
Och .html
<div *ngFor="let ages of result">
<strong>{{ages[0].age}}</strong>
<div *ngFor="let item of ages">
{{item.name}}
</div>
</div>
