【问题标题】:Angular form control value changes doesn't notify角度表单控件值更改不通知
【发布时间】:2018-11-04 19:57:45
【问题描述】:

我有一个订阅了 valueChanges observable 的基本表单控件。

@Component({
  selector: 'my-app',
  template: `
       <input [formControl]="control" />
       <div>{{ name$ | async | json }}</div>
   `
})
export class AppComponent implements OnInit {
  name$: Observable<string>;
  control;

  constructor(private builder: FormBuilder) {
    this.control = this.builder.control('');
  }

  ngOnInit() {
    this.name$ = this.control.valueChanges
      .pipe(
        map((name) => {
          console.log('fired', name)
          return name;
        })
      );


    this.control.setValue('2');
  }
}

当我调用 setValue 时,观察者没有收到任何通知。似乎异步管道不起作用。如果我将 setValue 包装在 setTimeout 中,它就可以工作。为什么会这样?

我也尝试添加 shareReplay() 也不起作用。

【问题讨论】:

    标签: angular typescript rxjs


    【解决方案1】:

    这个问题的解决方案

    this.control.setValue('2'); // I move any changes at the top for startWith operater 
    this.name$ = this.control.valueChanges
      .pipe(
        startWith(this.control.value),
        map((name) => {
          console.log('fired', name)
          return name;
        })
      );
    

    另一种在没有async 运算符的情况下使其工作的方法这意味着我在控制值更改为“2”之前订阅了值更改,并且我稍后会捕获所有更改

    this.control.valueChanges
      .pipe(
        map((name) => {
          console.log('fired', name)
          return name;
        })
      )
      .subscribe ( v => this.value = v )
    

    模板

    {{value}}
    

    为什么异步问题中的示例不起作用,异步操作员将订阅可观察对象,但在异步订阅时,控件的当前值将是“2”,因此没有改变为什么第一个值会不作为表单控件的更改发出,可观察到的另一件事是惰性的,因此当您订阅时,您获得的值之前的任何更改都不会被看到

    【讨论】:

    • 你是什么意思?异步管道应该订阅并显示第一个值。
    • 否,如果订阅发生在值更改之后,当你订阅他运行时,observable 是懒惰的异步管道将使用异步管道运行来创建它
    【解决方案2】:

    当您从ngOnInit 调用视图时,它不起作用的原因是视图尚未初始化(html 标记)。 你需要添加到ngAfterViewInit():

    import AfterViewInit from '@angular/core';
    export class AppComponent implements AfterViewInit{ 
       ngAfterViewInit() {
        this.name$ = this.control.valueChanges
          .pipe(
            map((name) => {
              console.log('fired', name)
              return name;
            })
          );
    
    
        this.control.setValue('2');
      }
    }
    

    你需要测试它,我没有

    【讨论】:

      【解决方案3】:

      如果你想在 Angular 中观察到来自控制值的一般解决方案:

      this.value$ = defer(() => {
        return this.control.valueChanges.pipe(startWith(this.control.value));
      });
      

      通过使用defer,您可以确保您的 startWith 值将是您订阅 observable 时表单的实际值。如果您没有使用defer,那么您的 startWith 值将只是您的 observable 创建(未订阅)时表单的值。

      如果您想在您的应用程序中重用该逻辑,您可以将该逻辑放入 utils 函数中:)

      // utils.ts
      export function observeControlValue$(formControl: AbstractControl): Observable<any> {
          return defer(() => {
              return formControl.valueChanges.pipe(startWith(formControl.value));
          });
      }
      
      // component.ts
      this.value$ = observeControlValue$(this.control);
      

      【讨论】:

        【解决方案4】:

        如果你想使用响应式表单,你应该使用 FormControl 而不是 FormBuilder。

        你的控件应该这样初始化:

        export class AppComponent implements OnInit {
        public control = new FormControl('');
        

        HTML 是:&lt;input type="text" [formControl]="control"&gt;

        那你就不需要Observable&lt;string&gt;了,直接用

        <div>{{ control.value | json }}</div>
        

        详见 ReactiveForm 文档:https://angular.io/guide/reactive-forms

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-01-13
          • 2020-10-04
          • 1970-01-01
          • 2022-01-21
          • 1970-01-01
          • 1970-01-01
          • 2018-01-31
          • 1970-01-01
          相关资源
          最近更新 更多