【问题标题】:ngModelChange not called when changing the model from component从组件更改模型时未调用 ngModelChange
【发布时间】:2021-09-18 17:23:09
【问题描述】:

我是 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,但是如果我有一个带有很多控制器的表单,那就太混乱了,可以从不同的方法调用相同的操作。

【问题讨论】:

    标签: angular typescript angular-material


    【解决方案1】:

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

    (ngModelChange) 是 ngModel 指令的 @Output。什么时候开火 模型改变了。

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

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

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

    【讨论】:

    • 正如我在问题中所说,我不想在 changeField2 中调用 changeField3 或以相同的方法更新值,因为我有几个输入,所有控制器都依赖于所有控制器。在您的示例中,您使用的是combineLatest,当两者都有值时,它似乎连接了这些值。有没有其他方法可以用来监听控制器的变化?
    • 我认为这是ngModel 的唯一解决方案,因为您只能在实际输入时收听ngModelChanges
    • 您还可以查看一个不错的 Angular 反应表单包github.com/ngneat/reactive-forms
    • 不使用任何其他软件包就没有办法做到这一点吗?例如,这可以通过使用响应式表单来完成?
    【解决方案2】:

    在这种情况下,您可以在 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'; 
      }
    

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

    【讨论】:

    • 嗨,谢谢你的回答,这对我的情况很有用,但它只有在失去输入焦点时才会执行,是否每次输入改变时它都会执行(如 onKeyPress例如)?
    • 在您的情况下,我们没有任何选择使用“(更改)”,但是如果您使用 Reactive 表单或 Formly 用于此表单,您可以听取每个更改
    【解决方案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);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-09-27
      • 1970-01-01
      • 1970-01-01
      • 2019-10-04
      • 2018-02-02
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多