Angular2 表单控件 valueChanges 可观察完成从未调用

Angular2 form control valueChanges observable complete never called

我目前正在尝试在搜索过程中在我的搜索栏上显示一个简单的加载程序。我计划在我的表单控件可观察到的 valueChanges 的订阅回调中将一个变量设置为一个值 "loading",并在完整的回调中将其设置为一个空字符串。但是,永远不会调用完整的回调。

我也尝试在 finally 上添加一个回调,但它也从未被调用过。

我的代码:

searchBox: Control = new Control();
loadingClass: string = "";

constructor() {
    this.searchBox.valueChanges
            .debounceTime(400)
            .distinctUntilChanged()
            .subscribe((text: string) => {
                this.imageSearch = text;
                this.loadingClass = "loading";
            }, (err: Error) => {
                console.log(err);
            }, () => {
                this.loadingClass = "";
                console.log("test");
            });
}

这是正常的,因为 observable 永远不会完成。 valueChanges 允许您从搜索框中接收值。事实上,您希望在搜索操作完成时收到通知。

所以我会尝试类似的方法,假设 searchImage 确实进行了搜索并且 return 是一个可观察的:

constructor() {
  this.searchBox.valueChanges
              .debounceTime(400)
              .distinctUntilChanged()
              .flatMap((text:string) => { // <-------
                this.loadingClass = "loading";
                return this.searchImage(text);
              })
              .subscribe((searchResult) => {
                  this.imageSearch = searchResult;
                  this.loadingClass = ""; // <----
              }, (err: Error) => {
                  console.log(err);
              });
}

flatMap运算符的使用见这篇文章:

我发现我正在尝试错误的方法。相反,我意识到我的 observable 上有 debounceTime,所以我在我的输入控件上注册了一个 keyup 事件,并在其中将 loadingClass 的值设置为 "loading",并且在我的订阅中,我将值设置回空字符串。

我希望这可以引导一些人更好地理解 Angular2 表单。 Angular 有两种不同的构建形式的方法(反应式和模板形式)。没有意识到这一点可能会导致您使用混乱的应用程序。

valuesChages 是指令 NgModel 的 属性,class FormControl(记住这一点)。

The reactive approaches use the ReactiveFormsModule import (your.module.ts):

import {ReactiveFormsModule} from '@angular/forms';

@NgModule({
  ...
  imports: [
    ...
    ReactiveFormsModule,
    ...
  ],
  ...
})

通过这种方式,您可以在表单控件 (template.component.html) 上使用 [(formControl)] 属性。

<input type="text" class="form-control" id="searchBox"
       required
       [(formControl)]="searchBox"/> 

Template-driven approached (your.module.ts):

import {FormsModule} from '@angular/forms';

    @NgModule({
      ...
      imports: [
        ...
        FormsModule,
        ...
      ],
      ...
    })

这个方法有它自己的表单控件属性,ngModel (your.template.ts):

<input type="text" class="form-control" id="searchBox"
       required
       [(ngModel)]="searchBox"/>