Angular2-使用Switchmap从init的服务中获取数据 [英] Angular2 - get data from service on init with Switchmap

查看:61
本文介绍了Angular2-使用Switchmap从init的服务中获取数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Angular 2进行术语搜索.这与《英雄指南》中使用的代码相同.

I'm doing a term search with Angular 2. It's about the same code used in the Heroes tutorial.

我的服务:

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[]>([]);
        });
}

如果我在输入对话框中输入一些文本,它会很好地工作.问题是,我想在输入任何内容之前得到一些结果.在上面的代码中,我添加了这一行

It works well if I type some text in the input dialog. Problem is, I want to have some results before typing anything. In the code above, I added the line

: this.bibliographieSearchService.search(null, "1", "20"))

为此,希望当term为null时将显示结果页面.但这仅在我清除输入对话框时才有效.我还尝试通过另一个服务功能在init上加载数据.但是,搜索不再起作用.

for this purpose, hoping that a page of results would be shown when term is null. But it only works when I clear the input dialog. I also tried to load the data on init with another service function. But then, the search does not work anymore.

有什么主意吗?

推荐答案

解决方案的问题是 this.searchTerms 可能是 valueChanges 的可观察值.输入中的值不变,正在发出任何事件.

The problem with your solution is that this.searchTerms is probably an Observable of valueChanges, so until the value inside the input does not change, any event is being emitted.

比方说,您想在每次输入获得焦点时以及每次值更改时都触发搜索.

Let's say you want to trigger the search each time that the input is being focused, and also each time that the value is changing.

因此,在这种情况下,您还需要监听焦点事件,以便在由输入触发焦点事件时能够发出值.但是,您始终需要获取 valueChanged 发出的最后一个值.在这种情况下, combineLatest 运算符很有道理,因此您可以同时关注重点和价值变化. combineLatest 运算符发出每个源Observables的最新值,因此即使在发出 focus 事件时,您也会从 this接收到最后一个.searchTerms .

So, in this case, what do you need is to listen to the focus event as well, to be able to emit a value when the focus event is triggered by the input. But you always need to take the last value that valueChanged emitted. In this case a combineLatest operator would make sense, so you listen to both the focus and the value change. The combineLatest operator emits the latest values of each source Observables, so even in when the focus event is the one that emits, you will receive the last one from this.searchTerms.

要收听焦点事件,您将需要在输入中使用@ViewChild,以在组件中获取引用.

To be able to listen to the focus event, you will need to use @ViewChild on your input, to get a reference in your component.

// html
<input ... #myComponent>

// ts

export class MyComponent {
  @ViewChild('myComponent') myComponent;
  myComponentFocus$: Observable;

  constructor () {}
}

然后,您可以在ngOnInit函数中创建输入焦点事件的可观察对象,

Then you can create an observable of the focus event of your input in the ngOnInit function,

ngOnInit(): void {
  this.myComponentFocus = Observable.fromEvent(this.myComponent.nativeElement, 'focus')
  ...
}

现在您的参考书目将是这样的:

Now your bibliographies would be something like:

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[]>([]);
    });

,此解决方案仍然存在问题.在所有组合的Observables都发出任何值之前, combineLatest 不会发出,因此我们的this.bibliographies仍然需要先更改值才能发出任何值.

BUT, there is still a problem with this solution. combineLatest won't emit until all the Observables combined have emitted any value, so our this.bibliographies will still need for the value change to emit before emitting anything.

要解决此问题,我们可以创建一个 null 的Observable,然后将 this.searchTerms 与此空Observable关联.这意味着新的Observable将从开始就具有一个值(null),因此,在发出 focus 事件时,也会发出 this.bibliographies Observable.

To solve that, we can create an Observable of null, and then concat this.searchTerms to this null Observable. This means the new Observable will have a value (null) from the beginning, so when focus event is emitted, this.bibliographies Observable will emit as well.

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[]>([]);
        });
      }

例如,如果您只想使用事件的第一个焦点,而不是所有其他对象,则可以在可观察到的焦点事件中添加 take(1).

If, for instance, you only want to use the first focus of the event and not all the others, you can add a take(1) to the focus event observable.

这篇关于Angular2-使用Switchmap从init的服务中获取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆