我的情况很简单。有两个字段的html表单:

  • 名字
  • lastName

  • 我希望lastName在用户更改firstName时有所改变。我通过Angular(8)中可观察到的valueChanges实现了它。

    此外,我有两个订阅来监听和记录更改:
  • 完整表格上的一种
  • 一个关于lastName

  • 这是它的实现方式:

     ngOnInit(){
        this.form = new FormGroup({
          firstName: new FormControl('', {updateOn: 'blur'}),
          lastName: new FormControl('', {updateOn: 'blur'}),
        });
        this.form.get('lastName').valueChanges.subscribe(value => console.log('lastName', value));
        this.form.valueChanges.subscribe(value => console.log('Value', value));
    
        this.form.get('firstName').valueChanges
          .subscribe(firstName => {
            this.form.get('lastName').setValue(`firstName ${firstName} ${new Date().getMilliseconds()}`);
          });
      }
    

    通常,从用户的角度来看,这的行为符合预期。用户更改firstName,然后lastName自行更改。

    但是,当我查看控制台日志时,这是我得到的:
    lastName firstName test 850
    Value > {firstName: "test", lastName: "firstName test 850"}
    Value > {firstName: "test", lastName: "firstName test 850"}
    

    我希望从整体上得到两个日志,但是一个名字更改了,第二个姓氏更改了。
    像这样:
    Value > {firstName: "test", lastName: ""}
    lastName firstName test 850
    Value > {firstName: "test", lastName: "firstName test 850"}
    

    这是stackblitz的完整示例。

    好的,所以当我改变一种方式时,从这里更新lastName:
    this.form.get('lastName').setValue(`firstName ${firstName} ${new Date().getMilliseconds()}`);
    

    对此:
    setTimeout(() => this.form.get('lastName').setValue(`firstName ${firstName} ${new Date().getMilliseconds()}`));
    

    然后按照我期望的顺序进行日志:
    Value > {firstName: "test", lastName: ""}
    lastName firstName test 850
    Value > {firstName: "test", lastName: "firstName test 850"}
    

    但是,setTimeout在这里似乎很棘手。
    这是stackblitz的完整代码。

    问题是:
    这里发生了什么?为什么FormGroups以这种方式工作?
    是否有一种模式可以在Angular中处理此类事件(当一种形式影响另一种形式时)?

    最佳答案

    这就是事件循环的工作方式

    两种情况都发生了什么:

    没有setTimeout

  • 用户设置的名字firstname
  • firstName.valueChanges已添加到EventLoop队列
  • EventLoop运行并调用操作firstName.valueChanges
  • lastName.setValue称为
  • lastName.setValuelastName.valueChangesform.valueChanges添加到eventLoop队列
  • lastName.valueChangesform.valueChanges添加到eventLoop队列
  • lastName.valueChanges已出列
  • form.valueChanges(来自lastName.valueChanges)已出队
  • form.valueChanges(来自firstName.valueChanges)已出队

  • 使用setTimeout
  • 用户设置的名字
  • firstName.valueChanges已添加到EventLoop队列
  • EventLoop运行并调用操作firstName.valueChanges
  • setTimeout(lastName.setValue)未调用,但已添加到事件循环队列
  • firstName.valueChangesform.valueChanges添加到事件循环队列
  • setTimeout出队,他设置lastName值并将lastName.valueChanges添加到tevent循环队列
  • form.valueChanges(来自firstName.valueChanges)已出队
  • lastName.valueChanges出队,并将form.valueChanges添加到事件循环队列
  • form.valueChanges(来自lastName.valueChanges)已出队
  • 10-06 12:26