我正在使用Angular 2进行术语搜索。它与英雄教程中使用的代码相同。
我的服务:
search(term: string = null, page: string = null, limit: string = null): Observable<Bibliographie[]> {
let params = new URLSearchParams();
if (term) params.set('q', term);
if (page) params.set('_page', page);
if (limit) params.set('_limit', limit);
return this.http
.get('http://localhost:3000/bibliographie', {search: params})
.map(response => response.json() as Bibliographie[])
.catch(this.handleError);
}
我的组件:
ngOnInit(): void {
this.bibliographies = this.searchTerms
.debounceTime(300)
.switchMap(term => term
? this.bibliographieSearchService.search(term)
: this.bibliographieSearchService.search(null, "1", "20"))
.catch(error => {
console.log(error);
return Observable.of<Bibliographie[]>([]);
});
}
如果我在输入对话框中输入一些文本,它会很好用。问题是,我想在输入任何内容之前得到一些结果。在上面的代码中,我添加了行
: this.bibliographieSearchService.search(null, "1", "20"))
为此目的,希望当term为null时显示一页结果。但它只在我清除输入对话框时才有效。我还尝试使用其他服务功能在init上加载数据。但是,搜索不再起作用了。
有什么想法吗?
答案 0 :(得分:1)
你的解决方案的问题是this.searchTerms
可能是valueChanges
的Observable,所以在输入内的值没有改变之前,任何事件都会被发出。
假设您希望每次输入被聚焦时触发搜索,并且每次值都在改变时触发搜索。
因此,在这种情况下,您还需要监听焦点事件,以便在输入触发焦点事件时发出值。但是你总是需要取valueChanged
发出的最后一个值。在这种情况下,combineLatest运算符是有意义的,因此您可以同时关注焦点和值的变化。 combineLatest
运算符会发出每个源Observable的最新值,因此即使focus
事件是发出的事件,您也会收到来自this.searchTerms
的最后一个事件。
为了能够收听焦点事件,您需要在输入中使用@ViewChild,以获得组件中的引用。
// html
<input ... #myComponent>
// ts
export class MyComponent {
@ViewChild('myComponent') myComponent;
myComponentFocus$: Observable;
constructor () {}
}
然后你可以在ngOnInit函数中创建输入焦点事件的observable,
ngOnInit(): void {
this.myComponentFocus = Observable.fromEvent(this.myComponent.nativeElement, 'focus')
...
}
现在你的参考书目会像:
this.bibliographies = Observable.combineLatest(this.searchTerms, this.myComponentFocus)
.debounceTime(300)
.switchMap(([focusEvt, term]) => term
? this.bibliographieSearchService.search(term)
: this.bibliographieSearchService.search(null, "1", "20"))
.catch(error => {
console.log(error);
return Observable.of<Bibliographie[]>([]);
});
但是,此解决方案仍然存在问题。 combineLatest
不会发出,直到所有Observable组合都发出任何值,因此我们的this.bibliographies仍然需要在发出任何值之前发出值更改。
要解决这个问题,我们可以创建一个Observable of null ,然后将this.searchTerms
连接到此null Observable。这意味着新的Observable将从头开始具有值(null),因此当发出focus
事件时,this.bibliographies
Observable也会发出。
ngOnInit(): void {
this.myComponentFocus = Observable.fromEvent(this.myComponent.nativeElement, 'focus')
this.searchTermsWithNull = Observable.of(null).concat(this.searchTerms)
this.bibliographies = Observable.combineLatest(this.searchTermsWithNull, this.myComponentFocus)
.debounceTime(300)
.switchMap(([focusEvt, term]) => term
? this.bibliographieSearchService.search(term)
: this.bibliographieSearchService.search(null, "1", "20"))
.catch(error => {
console.log(error);
return Observable.of<Bibliographie[]>([]);
});
}
例如,如果您只想使用事件的第一个焦点而不是所有其他焦点,则可以向焦点事件observable添加take(1)
。
答案 1 :(得分:0)
上面答案的最后一个元素没有焦点部分(我认为因为没有子元素)!这是我的新ngOnInit函数:
...
private searchTermsWithNull;
...
ngOnInit(): void {
this.searchTermsWithNull = Observable.of(null).concat(this.searchTerms);
this.bibliographies = this.searchTermsWithNull
.debounceTime(300)
.switchMap(term => term
? this.bibliographieSearchService.search(term)
: this.bibliographieSearchService.search(null, "1", "20"))
.catch(error => {
console.log(error);
return Observable.of<Bibliographie[]>([]);
});
}