J'essaie de fusionner 2 requêtes HTTP en Angular/TypeScript, mais j'ai du mal à le faire fonctionner. La situation est illustrée à l'aide du tutoriel Angular 2/4 Tour of Heroes, qui utilise un Observable pour rechercher des héros par valeur "name" (https://angular.io/tutorial/toh-pt6#add-the-ability-to-search-by-name). Le code de héros-search.service.ts est comme suit:Comment fusionner 2 recherches dans le tutoriel Angular Heroes?
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { Hero } from './hero';
@Injectable()
export class HeroSearchService {
constructor(private http: Http) {}
search(term: string): Observable<Hero[]> {
return this.http
.get(`api/heroes/?name=${term}`)
.map(response => response.json().data as Hero[]);
}
}
que je dois faire l'équivalent d'ajouter une deuxième valeur de chaîne pour « synonyme » à la classe Hero:
export class Hero {
id: number;
name: string;
synonym: string;
}
et ajouter un synonyme à chaque héros:
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const heroes = [
{ id: 0, name: 'Zero', synonym: 'little' },
{ id: 11, name: 'Mr. Nice', synonym: 'pleasant' },
{ id: 12, name: 'Narco', synonym: 'sleep' },
{ id: 13, name: 'Bombasto', synonym: 'loud' },
{ id: 14, name: 'Celeritas', synonym: 'vegetable' },
{ id: 15, name: 'Magneta', synonym: 'color' },
{ id: 16, name: 'RubberMan', synonym: 'hose' },
{ id: 17, name: 'Dynama', synonym: 'motor' },
{ id: 18, name: 'Dr IQ', synonym: 'smart' },
{ id: 19, name: 'Magma', synonym: 'volcanic' },
{ id: 20, name: 'Tornado', synonym: 'wind' }
];
return {heroes};
}
}
Je peux alors rechercher en héros-search.service.ts par synonyme en substituant:
.get(`api/heroes/?synonym=${term}`)
Ma question est comment chercher le nom et le synonyme et renvoyer des correspondances avec le nom ou le synonyme. À partir de la documentation de ReactiveX, il semble que la réponse est d'utiliser l'opérateur Merge: http://reactivex.io/documentation/operators/merge.html
Cependant, j'ai du mal à faire fonctionner ça. J'ai essayé différentes façons d'utiliser la fusion, y compris la nouvelle version du code de héros search.service.ts ci-dessus qui suit:
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/merge';
import { Hero } from './hero';
@Injectable()
export class HeroSearchService {
constructor(private http: Http) {}
search(term: string): Observable<Hero[]> {
const nameResults = this.http.get(`api/heroes/?name=${term}`);
const synonymResults = this.http.get(`api/heroes/?synonym=${term}`);
nameResults.merge(synonymResults);
return nameResults.map(response => response.json().data as Hero[]);
}
}
Le code non-travail est correctement à https://plnkr.co/edit/4mrL5ReQCSvuzOODixJU?p=preview.
Je ne vois aucune preuve que la fusion a réussi et nameResults ne donne que des noms, pas des synonymes. Aucun message d'erreur n'apparaît.
Le code RxJS à http://reactivex.io/documentation/operators/merge.html utilise le code de la forme
const mergedResults = Rx.Observable.merge(nameResults, synonymResults);
mais lorsque je tente un code tel que j'obtiens une erreur signalée:
Impossible de trouver le nom 'Rx'
Donc mes questions sont:
Comment peut-on utiliser RxJS merg e ici?
Y a-t-il une autre approche utilisant RxJS qui soit plus appropriée?
Existe-t-il une autre approche au niveau de la classe Hero qui fonctionnera, par exemple en calculant namePlusSynonym sans avoir à ajouter namePlusSynonym à chaque ligne du tableau Hero? ADDENDUM: suggestions ici et code http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-merge J'ai créé une nouvelle version de hero-search.service.ts avec les sorties de la console.
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/merge';
import { Hero } from './hero';
@Injectable()
export class HeroSearchService {
constructor(private http: Http) {}
search(term: string): Observable<Hero[]> {
const nameResults = this.http.get(`api/heroes/?name=${term}`);
nameResults.subscribe(nameData => console.log('nameData', nameData));
const synonymResults = this.http.get(`api/heroes/?synonym=${term}`);
synonymResults.subscribe(synonymData => console.log('synonymData', synonymData));
const combinedResults = nameResults.merge(synonymResults);
combinedResults.subscribe(combinedData => console.log('combinedData', combinedData));
return combinedResults.map(response => response.json().data as Hero[]);
}
}
Mais il n'affiche que synonymResults, pas nameResults. Les deux noms nameResults et synonymResults me semblent OK dans la sortie de la console, mais combinedResults n'a que des données et l'URL pour les résultats des synonymes et ne semble pas affecté par la méthode de fusion.J'ai également essayé avec la concaténation, avec des résultats similaires.
Il semble que je ne suis pas combiner au bon moment, mais la combinaison à un stade différent donne le même résultat, montrant seulement synonymes:
search(term: string): Observable<Hero[]> {
const nameResults = this.http.get(`api/heroes/?name=${term}`).map(response => response.json().data as Hero[]);
nameResults.subscribe(nameData => console.log('nameData', nameData));
const synonymResults = this.http.get(`api/heroes/?synonym=${term}`).map(response => response.json().data as Hero[]);
synonymResults.subscribe(synonymData => console.log('synonymData', synonymData));
const combinedResults = nameResults.merge(synonymResults);
combinedResults.subscribe(combinedData => console.log('combinedData', combinedData));
return combinedResults;
}
Il semble un peu inhabituel d'utiliser deux requêtes HTTP, puis de les fusionner côté client. Normalement, je m'attendrais à voir quelque chose comme 'api/heroes? Synonym = $ {synonym} & name = $ {name}'. Cependant, je pense qu'une chose qui vous manque est 'nameResults = nameResults.merge (synonymResults);' Vous ignorez le retour de fusion qui est l'observable fusionnée. – Pace
Ou mieux encore, 'let combinedResults = nameResults.merge (synonymResults)', puis retournez 'combinedResults.map (...)' – Pace
Changement des deux dernières lignes en 'const combinéResults = nameResults.fusionner (synonymResults); return combinedResults.map (réponse => response.json(). Données comme Hero []); 'aboutit au fonctionnement synonyme mais pas au nom. –