1: N or N: 1 relations of two objects in Angular2 as observed from an http request

Referring to the Tour of heroes from the angular tutorial.

It is assumed that we will provide all existing heroes with the opportunity to wear a special suite, but any other hero can wear the same suite. We really do not want them to be naked. In this case, we will have a related data object that contains all the information about the available costumes. The hero himself must know what suite he wears, and where he can find his chosen one. For this case, we would create a property that contains the identifier of his chosen dress.

What would be the correct way to allow the connection between the hero and his package in angular as observed from the http request?

eg:

app/hero.ts

 export class Hero { id: number; name: string; suiteId: number; } 

app/suit.ts

 export class Suite { id: number; name: string; material: string; color: string; } 

app/in-memory-data.service.ts

 import { InMemoryDbService } from 'angular-in-memory-web-api'; export class InMemoryDataService implements InMemoryDbService { createDb() { let heroes = [ {id: 11, name: 'Mr. Nice', suitId: 11}, {id: 12, name: 'Narco', suitId: 12} ]; let suits= [ {id: 11, name: 'Nice and blue', material: 'Cotton', color: 'blue'}, {id: 12, name: 'Sexy and red', material: 'Silk', color: 'red'} ]; return {heroes, suits}; } } 

I know that something like the following block of code will work, but I would like to know how to resolve this โ€œobservableโ€ method.

 // ... getHeroesWithSuit(): Observable<Hero[]> { return this.http.get(this.heroesUrl) .map( response => response.json().data as Hero[]) .do( response => response.forEach( ( data ) => data.suite = this.suiteService .getSuit(data.suiteId) .subscribe(suite => data.suite = suite as Suite) )) .catch(this.handleError); } // ... 
+5
source share
1 answer

The getHeroesWithSuit() method performs two tasks.

  • Get a list of heroes.
  • Get set details for each hero.

And since we want to combine these two operations, we need to use the flatMap and forkJoin . Using these two statements, the getHeroesWithSuit() function can be written as follows:

  getHeroesWithSuit(): Observable<Hero[]> { return this.http.get(this.heroesUrl) .map(response => response.json().data as Hero[]) .flatMap((heroes: Heroes[]) => Observable.forkJoin(heroes.map((hero: Hero) => { return this.suiteService.getSuit(hero.suiteId) .map((suite: Suite) => { hero.suite = suite; return hero; }); })) ); } 

flatMap The operator allows you to bind two observables, returning a new Observable. here we bind the result of getting the heroes service to the observable forkJoined.

And then we mapped each hero to the getSuite() suiteServices and passed the result to the forkJoin operator.

the above code snippet represents an N: 1 ratio, where each character has one set.

but what if each hero has several sets, and the suiteId class's suiteId field is Array. In this case, we must use the forkJoin operator again to get information about all the packages for each hero.

In this forkJoin we map all the suiteId each hero to the getSuit() suiteServices . And this will be a 1: N ratio between objects. The getHeroesWithSuit() update function will look like this.

  getHeroesWithSuit():Observable<Hero[]> { return this.http.get(this.heroesUrl) .map(response => response.json().data as Hero[]) .flatMap( (heroes:Heroes[]) => Observable.forkJoin(heroes.map( (hero:Hero) => { return Observable.forkJoin(hero.suiteIds.map( suiteId => { return this.suiteService.getSuit(suiteId) } )).map( suites => { hero.suites = suites; return hero; }) } )) ); } 

here is the link, it has a good explanation of the operators and how to use them to combine several observables. Hope this helps.

+7
source

Source: https://habr.com/ru/post/1266170/


All Articles