我正在学习Angular 4并遇到了一个我似乎无法找到解决方案的问题。以下是上下文: 我有一个简单的应用程序,显示有关美国总统的信息。 后端是webapi提供的rest API ...这很好用。 前端是一个Angular应用程序。
我已将问题简化为3个组件,1个数据服务和1个模型。 这是模型:
export class President {
constructor(
public id: number,
public presidentName: string,
public presidentNumber: number,
public yearsServed: string,
public partyAffiliation: string,
public spouse: string) {}
}
3个组成部分 1. SearchComponent 2. HomeComponent 3.总裁成员
当app bootstraps时,它会加载ApplicationComponent - 它是根组件:
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<search-component></search-component>
<home-component></home-component>
`
})
export class ApplicationComponent {}
PresidentComponent是HomeComponent的子组件。当主组件加载时,它会对api进行http调用以获取总统列表,并为返回的每一行呈现1个presidentComponent。这很好。
我想要做的是实现一个搜索功能,其中dataService公开EventEmitter并提供搜索方法,如下所示:
import { Injectable, EventEmitter, Output } from '@angular/core'
import { President } from '../models/President'
import { Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class DataService {
constructor(private http: Http) {
}
searchEvent: EventEmitter<any> = new EventEmitter();
// simple property for the url to the api
get presidentUrl {
return "http://localhost:51330/api/presidents";
}
search(params: any): Observable<President[]> {
let encParams = encodeParams(params);
console.log(encParams);
return this.http
.get(this.presidentUrl, {search: encParams})
.map(response => response.json());
}
getParties(): String[] {
return ['Republican', 'Democrat', 'Federalist', 'Whig', 'Democratic-Republican', 'None'];
}
getPresidents(): Observable<President[]> {
return this.http.get(this.presidentUrl)
.map(response => response.json());
}
}
/**
* Encodes the object into a valid query string.
* this function is from the book Angular2 Development with TypeScript
*/
function encodeParams(params: any): URLSearchParams {
return Object.keys(params)
.filter(key => params[key])
.reduce((accum: URLSearchParams, key: string) => {
accum.append(key, params[key]);
return accum;
}, new URLSearchParams());
}
搜索组件包含搜索表单,单击搜索按钮时,它会执行onSearch()函数并在数据服务上调用emit:
onSearch(){
if(this.formModel.valid){
console.log('emitting event from search.ts');
this.dataService.searchEvent.emit(this.formModel.value);
}
}
然后,在HomeComponent中,我想订阅此事件并在触发时通过dataservice执行搜索:
ngOnInit(): void {
//when component loads, get list of presidents
this.dataService.getPresidents()
.subscribe(
presidents => {
console.log('sub');
this.presidents = presidents;
},
error => console.error(error)
)
//when search event is fired, do a search
this.dataService.searchEvent
.subscribe(
params => {
console.log('in home.ts subscribe ' + JSON.stringify(params));
this.result = this.dataService.search(params);
},
err => console.log("cant get presidents. error code: %s, URL: %s"),
() => console.log('done')
);
}
当我在浏览器中运行它时,除了从不执行http调用之外,一切正常。如果我订阅()到dataservice本身的http.get调用,它会执行,但是当我在HomeComponent上设置订阅时,为什么还要这样做呢? 我想在HomeComponent中处理Observable,并根据搜索结果更新UI中显示的总统列表。 非常感谢任何建议。
答案 0 :(得分:0)
在服务中使用EventEmitter的整个想法是不对的。 EventEmitter应与@Output属性一起使用,以将数据从子组件发送到其父组件。
即使EventEmitter是Subject的子类,您也不应该在服务中使用它。因此,将服务注入到组件中,在组件中订阅其observable,并在需要时使用EventEmitter向父组件发出事件。
答案 1 :(得分:0)
在代码this.result = this.dataService.search(params);
中,结果是可观察的。您尚未订阅。
在这种情况下,您应该使用async
管道来显示数据。
答案 2 :(得分:0)
为什么不使用Subject
中的rxjs
。以下是我的建议:
DataService:
import { Observable, Subject } from "rxjs";
import 'rxjs/add/operator/catch';
@Injectable()
export class DataService {
private _dataSubject = new Subject();
constructor(private http: Http) {
this.http.get(this.presidentUrl)
.map(response => this._dataSubject.next(response.json()))
.catch(err => this._dataSubject.error(err));
);
}
// simple property for the url to the api
get presidentUrl {
return "http://localhost:51330/api/presidents";
}
search(params: any){
let encParams = encodeParams(params);
console.log(encParams);
this.http
.get(this.presidentUrl, {search: encParams})
.map(response => this._dataSubject.next(response.json()))
.catch(err => this._dataSubject.error(err));
}
getParties(): String[] {
return ['Republican', 'Democrat', 'Federalist', 'Whig', 'Democratic-Republican', 'None'];
}
getPresidents(): Observable<President[]> {
return this._dataSubject;
}
SearchComponent:
onSearch(){
if(this.formModel.valid){
console.log('emitting event from search.ts');
this.dataService.search(this.formModel.value);
}
}
通过这些修改,您应该只能在homeCompoent中拥有1个订阅者,然后每次调用onSearch()
时都会发出新数据。