Refiriéndose al " Tour de los héroes " del tutorial angular.
Asumimos que le daremos a todos los héroes existentes la posibilidad de usar una suite especial, pero cualquier otro héroe también puede usar la misma suite. Realmente no queremos que estén desnudos. En este caso, tendríamos un objeto de datos relacionado que contiene toda la información sobre los trajes disponibles. El propio héroe tiene que saber qué traje lleva puesto y dónde puede encontrar el elegido. Para este caso, crearíamos una propiedad que contenga la identificación de su vestido elegido.
¿Cuál sería la forma correcta de resolver la relación entre el héroe y su suite en Angular como se puede observar desde la solicitud http?
P.ej:
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}; } }Sé que algo como el siguiente bloque de código funcionará, pero me gustaría saber cómo resolver esto de la manera "observable".
// ... 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); } // ...el método getHeroesWithSuit() realiza dos tareas.
Y como queremos combinar estas dos operaciones, necesitamos usar los operadores flatMap y forkJoin . Usando estos dos operadores, la función getHeroesWithSuit() se puede escribir de manera Observable como esta.
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 Operator le permite encadenar dos Observables, devolviendo un nuevo Observable. aquí estamos encadenando el resultado del servicio de recuperación de héroes al observable forkJoined.
Y luego asignamos cada héroe al método getSuite() de suiteServices y pasamos el resultado al operador forkJoin .
el fragmento de código anterior representa la relación N: 1 donde cada héroe tiene una suite.
pero ¿qué pasa si cada héroe tiene varias suites y el campo suiteId de la clase Hero es una matriz? En ese caso, tenemos que usar el operador forkJoin una vez más para recuperar la información de todas las suites para cada héroe.
En este forkJoin todos los suiteId de suite de cada héroe al método getSuit() de suiteServices . Y esta será la relación 1:N entre objetos. La función de actualización getHeroesWithSuit() se verá así.
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; }) } )) ); }aquí está el enlace de referencia que tiene una buena explicación de los operadores y cómo usarlos para combinar múltiples Observables. Espero que esto sea de ayuda.