szab.kel
szab.kel

Reputation: 2526

When to use RxJS Observable<Object[]> and Observable<Object>?

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

Answers (1)

Eliseo
Eliseo

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

Related Questions