实现异步预输入搜索的正确方法是什么?

What is the proper way to implement async typeahead search?

在我的 Angular 应用程序中,有一个 "Listings" 的页面。由于有数百个列表,结果一次只能加载 20 个,当用户滚动到底部并单击 更多.

时会加载更多列表

我想在列表上方放置一个搜索框,它可以将更具体的搜索词发送到服务器,仅发送给 return 个匹配的列表。

例如,当用户在搜索框中输入 "myterm" 时,Angular 应将 GET 发送到 https://myapp.com/listings/?search=myterm 并仅在“列表”页面。

我不确定在 Angular 2+ 中执行此操作的正确方法是什么。在 AngularJS 中,每次按下 Search 时,我都会简单地触发一个新请求 returning 一个 promise,但我怀疑 Angular2+ 有一个不同的方法。我似乎找不到任何关于它的文献。

到目前为止,我刚刚在使用空搜索参数调用服务的组件中进行了初始函数调用(又名,获取所有内容)

ngOnInit() {
  this.listings = this.listingService.getListings('');
}

我建议使用 ReactiveFormsModule,因为它很容易解决这个问题。

首先,让我们定义我们的 FormGroup,它将包含一个表单控件。

form: FormGroup;

constructor(formBuilder: FormBuilder){
    this.form = formBuilder.group({
        search: ''
    });
}

现在我们已经定义了我们的简单表单,我们感兴趣的是在用户键入时发送请求,所以基本上只要我们的表单控件的值发生变化。我们可以像这样订阅 valueChanges Observable:

ngOnInit(){
    this.form.get('search').valueChanges
       .subscribe(value => this.listingService.getListings(value)));
}

这显然可行,但问题是我们不想为用户键入的每个字符发送请求。我们想等到他完成。我们可以使用 debounceTime 运算符来解决这个问题:

this.form.get('search').valueChanges
       .debounceTime(1000)
       .subscribe(value => this.listingService.getListings(value)));

我们还使用 switchMap 运算符来避免必须进行订阅链(因为 getListings 也是 returns 一个可观察的)。我们需要做的最后一件事是添加过滤器,因为我们不想发送带有空字符串的请求,假设用户删除了所有键入的内容。我们为此得到了 filter 运算符:

this.form.get('search').valueChanges
       .filter(value => value)
       .debounceTime(1000)
       .switchMap(value => this.listingService.getListings(value))
       .subscribe(listings => this.listings = listings);

模板应与此类似:

<form [formGroup]="form">
    <input type="text" formControlName="search">
</form>