从组件更改模型时未调用 ngModelChange

ngModelChange not called when changing the model from component

我是 Angular 的新手,我正在尝试了解如何连接不同的控制器,以便在控制器发生变化时更改控制器的值。

在这种特殊情况下,我有一个带有 ngModel 的表单,并尝试使用 ngModelChange 更新我模型中其他 属性 的值,问题是当用户与控件交互时调用 ngModelChange , 但在从组件更新模型时未被调用。

让我给你看一个示例代码。

https://stackblitz.com/edit/angular-ivy-z2q4mr

HTML 模板:

<form #f="ngForm" (ngSubmit)="onSubmit(f)">
  <mat-form-field appearance="fill">
    <mat-label>Field 1</mat-label>
    <input matInput name="field1" [(ngModel)]="MyItem.field1" (ngModelChange)="changeField2($event)">
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Field 2</mat-label>
    <input matInput disabled name="field2" [(ngModel)]="MyItem.field2" (ngModelChange)="changeField3($event)">
  </mat-form-field>
  
  <mat-form-field appearance="fill">
    <mat-label>Field 3</mat-label>
    <input matInput disabled name="field3" [(ngModel)]="MyItem.field3">
  </mat-form-field>
</form>

组件

import { OnInit, Component, ViewChild } from '@angular/core';


@Component({
  selector: 'app-component1',
  templateUrl: './component1.component.html',
  styleUrls: ['./component1.component.css']
})
export class Component1Component implements OnInit  {
  MyItem : any = {}

    constructor() {
      }
      
    ngOnInit(): void {
    }
    
    changeField2(event: any){
        this.MyItem.field2 = this.MyItem.field1 + " modification field 2"; //We can see that everytime field1 is changed is updating field2
    }
    
    changeField3(event: any) {
        this.MyItem.field3 = this.MyItem.field2 + " modification field 3"; //Eventhough we are updating field2, this is not being called
    }
}

如果我更改了 field1(因为它与 field2 相关),我希望 field3 会自动更新。当然,我考虑过在 changeField2 上调用 changeField3,但是如果我有一个包含很多控制器的表单,这太混乱了,可以从不同的方法调用相同的操作。

Field3 不会更新,因为您没有在 Field2 中输入任何内容。

(ngModelChange) is the @Output of ngModel directive. It fires when the model changes.

为了使您的示例正常工作,您必须在第一个字段发生变化时同时改变第三个字段和第二个字段

  changeField2(event: any) {
    this.MyItem.field2 = this.MyItem.field1 + ' modification field 2'; 
    this.MyItem.field3 = this.MyItem.field2 + ' modification field 3';
  }

另一种实现你想要的方法是使用ReactiveForms Playground

在这种情况下,您可以在 HTML

中的表单标记中使用 (change)
<form #f="ngForm" (change)="changeField3()">
  <mat-form-field appearance="fill">
    <mat-label>Field 1</mat-label>
    <input matInput name="field1" [(ngModel)]="MyItem.field1" (ngModelChange)="changeField2($event)">
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Field 2</mat-label>
    <input matInput disabled name="field2" [(ngModel)]="MyItem.field2" >
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Field 3</mat-label>
    <input matInput disabled name="field3" [(ngModel)]="MyItem.field3">
  </mat-form-field>
</form>

并在 Ts

  changeField3() {
   
    this.MyItem.field3 = this.MyItem.field2 + ' modification field 3'; 
  }

这种方法会监听表单模型中的每一个变化

我能够使用反应形式和 属性 ValueChanges 来做我需要的事情来捕捉控制器值何时发生变化。即使组件中的方法更改了控制器值,也会执行此操作。

这里有使用反应形式的相同示例: https://stackblitz.com/edit/angular-ivy-gh7zho

HTML 模板:

<form [formGroup]="testForm" (ngSubmit)="onSubmit()">
  <mat-form-field appearance="fill">
    <mat-label>Field 1</mat-label>
    <input matInput name="field1" formControlName="field1" />
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Field 2</mat-label>
    <input matInput name="field2" formControlName="field2" />
  </mat-form-field>

  <mat-form-field appearance="fill">
    <mat-label>Field 3</mat-label>
    <input matInput name="field3" formControlName="field3" />
  </mat-form-field>

  <button type="submit">Submit</button>
</form>

<button (click)="resetField2()">Reset field2</button>

组件

import { OnInit, Component, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  testForm: FormGroup = this.fb.group({
    field1: [{ value: '', disabled: false }, Validators.required],
    field2: [{ value: '', disabled: true }, Validators.required],
    field3: [{ value: '', disabled: true }, Validators.required]
  });
  constructor(private fb: FormBuilder) {
    const field1 = this.testForm.get('field1');
    const field2 = this.testForm.get('field2');

    field1!.valueChanges.subscribe(val => {
      this.changeField2();
    });

    field2!.valueChanges.subscribe(val => {
      this.changeField3();
    });
  }

  changeField2() {
    this.testForm
      .get('field2')!
      .setValue(this.testForm.get('field1')!.value + ' modification field 2'); //We can see that everytime field1 is changed is updating field2
  }

  changeField3() {
    this.testForm
      .get('field3')!
      .setValue(this.testForm.get('field2')!.value + ' modification field 3'); //Eventhough we are updating field2, this is not being called
  }

  resetField2() {
    this.testForm.get('field2')!.setValue(''); //This should leave field2 with only modification field 3
  }

  onSubmit() {
    console.warn(this.testForm.value);
  }
}