【发布时间】:2018-02-15 09:30:40
【问题描述】:
我正在尝试在 Angular/TypeScript 中合并 2 个 HTTP 获取搜索,但我无法让它工作。
使用 Angular 2 / 4 Tour of Heroes 教程说明了这种情况,该教程使用 Observable 来搜索英雄的“名称”值 (https://angular.io/tutorial/toh-pt6#add-the-ability-to-search-by-name)。 hero-search.service.ts 中的代码如下:
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[]);
}
}
我需要做的相当于将“同义词”的第二个字符串值添加到 Hero 类中:
export class Hero {
id: number;
name: string;
synonym: string;
}
并为每个英雄添加同义词:
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};
}
}
然后我可以通过替换来按同义词在 hero-search.service.ts 中搜索:
.get(`api/heroes/?synonym=${term}`)
我的问题是如何搜索名称和同义词并返回名称或同义词的匹配项。
从 ReactiveX 文档看来,答案似乎是使用 Merge 运算符:http://reactivex.io/documentation/operators/merge.html。但是,我无法使其正常工作。我尝试了各种使用合并的方法,包括上面新版本的 hero-search.service.ts 代码:
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[]);
}
}
无法正常工作的代码位于https://plnkr.co/edit/4mrL5ReQCSvuzOODixJU?p=preview。
我没有看到任何证据表明合并成功,并且 nameResults 只给出名称,而不是同义词。没有错误信息出现。
http://reactivex.io/documentation/operators/merge.html 处的 RxJS 代码使用以下形式的代码
const mergedResults = Rx.Observable.merge(nameResults, synonymResults);
但是当我尝试这样的代码时,我得到一个错误标记:
找不到名称“Rx”
所以我的问题是:
如何在这里使用 RxJS 合并?
还有其他更适合使用 RxJS 的方法吗?
在 Hero 类的级别上是否还有其他方法可以工作,例如计算 namePlusSynonym 而无需将 namePlusSynonym 添加到 Hero 数组中的每一行?
附录:按照此处的建议和http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-merge 的代码,我创建了一个带有控制台输出的新版本 hero-search.service.ts。
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[]);
}
}
但它只显示 synonymResults,而不是 nameResults。在控制台输出中,nameResults 和 synonymResults 对我来说都不错,但是 combineResults 只有数据和同义词结果的 url,并且似乎不受 merge 方法的影响。
我也尝试过 concat,结果相似。
似乎我没有在正确的阶段组合,但在不同的阶段组合会得到相同的结果,只显示同义词:
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;
}
【问题讨论】:
-
使用两个HTTP请求然后在客户端合并它们似乎有点不寻常。通常我希望看到像
api/heroes?synonym=${synonym}&name=${name}这样的东西。但是,我认为您缺少的一件事是nameResults = nameResults.merge(synonymResults);您忽略了合并的返回,这是合并后的 observable。 -
或者更好,
let combinedResults = nameResults.merge(synonymResults)然后返回combinedResults.map(...) -
将最后两行更改为:
const combinedResults = nameResults.merge(synonymResults); return combinedResults.map(response => response.json().data as Hero[]);导致同义词有效,但名称无效。 -
它应该发出两次,每次 HTTP 调用一次。您的第二个结果是否有可能覆盖您的第一个?如果您想将两个结果合并到一个列表中,您将需要类似...
let combinedResults = nameResults.merge(synonymResults).reduce((a, b) => a.concat(b)); -
建议的行在 IDE 中被标记为错误:“响应”类型上不存在属性“concat”。我不熟悉这些操作,所以我很难排除故障。
标签: angular merge get rxjs reactivex