Reputation: 2526
Using Angular 6, I defined my services based on the hero app. If a method should return multiple values, I always return an Observable<A[]>
and if I expect a single return, like if the method is for example getById
, I return Observable<A>
.
Problem is, today I wanted to do a groupBy()
on one of the returned array of values and all the examples I could find just use Observable<A>
instead of Observable<A[]>
, like this one. Also, looking at the answers here (I tried it, this only works on ~Observable<A>
) and the RxJS introduction (Observable: represents the idea of an invokable collection of future values or events.
), it seems I should have used Observable<A>
for collection like server returns, but than what do I use for single value returns?
Example services:
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));
}
Update:
I made a sample project. I can work with the array observables like this, but then I always need a mergeMap
. I understand, that if I use Observable<A[]>
, I will get all the values at once, since they are in an array, but if I use Observable<A>
, I get them one by one, which is why I cannot use it in an *ngFor
for example (expects array). Question is, do I always use A[]
when the server synchronously returns a collection and A
If I work with asynchronous data or do I need to consider other scenarios as well.
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));
}
}
Upvotes: 2
Views: 533
Reputation: 57929
I'm not sure that what do you want. If is a Group just 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());
}
And the .html
<div *ngFor="let ages of result">
<strong>{{ages[0].age}}</strong>
<div *ngFor="let item of ages">
{{item.name}}
</div>
</div>
Upvotes: 2