【问题标题】:Angular form change event with material components具有材料组件的角度形式更改事件
【发布时间】:2019-04-23 02:58:07
【问题描述】:

我有一个包含输入材料组件(如mat-selectmat-checkbox)的表单。

每次用户进行修改时,我都想将它们保存到数据库中。所以我做了类似<form (change)="save()">的事情。

这对于本机输入来说完美无缺,但是当用户更改材质组件值时它不会触发。

我宁愿避免在每个组件上使用<mat-select (selectionChange)="save()"> 之类的解决方案,因为当我必须更新我的表单时很容易忘记添加它。

编辑

这是一个模板驱动的表单。我的模板如下:

<form (change)="save()">
    <!-- Will trigger save -->
    <mat-form-field class="col">
        <input matInput placeholder="Name" name="name" [(ngModel)]="item.name">
    </mat-form-field>

    <!-- Will NOT trigger save -->
    <mat-form-field class="col">
        <mat-select placeholder="Category" name="category [(ngModel)]="item.category.id">
            <mat-option *ngFor="let category of categories" [value]="category.id">{{category.name}}</mat-option>
        </mat-select>
    </mat-form-field>

    <!-- ... -->
</form>

组件代码没有什么特别的,只有模型变量(item: Item;)。

【问题讨论】:

  • 你能显示你的组件代码吗?例如。你在使用响应式/模板驱动的表单吗?
  • @DaniilAndreyevichBaunov,我更新了我的问题。
  • 如果不需要模板驱动的表单,那么您可以考虑转换为响应式表单。这将允许您在 component.ts 代码中订阅表单本身的更改事件,而不是在 HTML 中使用一堆事件处理程序。如果您有兴趣,这里是文档的链接Reactive Forms - valueChanges
  • 我并没有真正看到使用响应式表单的优势,因为在我看来代码重复(因为我的模型对象已经存在)和 SoC 中的漏洞(因为背后的代码不应该注意模板上的内容)。我真的不明白这个问题,例如,mat-select 有一个双向绑定[()],因此应该触发 change 事件,对吧?

标签: angular forms angular-material onchange


【解决方案1】:

此解决方案适用于 Angular 11.2.1 和 Material 11.2.1

你需要用 valueChanges observable 来捕捉变化

this.editForm.valueChanges
 .subscribe(value=> {
       if (this.editForm.dirty) {
              //do something
              }
           });

注意事项:

  1. 通常你不需要放置过滤器 if(this.editForm.dirty) {...} ,因为正常行为是这个观察者只有在它被改变(脏)时才应该启动,但由于material components mat-xxx,这个观察者在 field 的值改变后被踢了几次,所以为了避免多次不必要的执行事件,你必须通过这个条件过滤 observable if (this.editForm.dirty) {。 ..} 它只会在更改后执行。

这同样适用于反应式表单,我刚刚注意到您的问题使用模板驱动,但值得注意的是,以防万一有人正在寻找反应式表单的解决方案。

【讨论】:

    【解决方案2】:

    使用change tracker 可以解决这个问题。

    检查以下示例:

    import { Component , KeyValueChanges, KeyValueDiffer, KeyValueDiffers, DoCheck, OnInit } from '@angular/core';
    
    @Component({
      selector: 'input-overview-example',
      styleUrls: ['input-overview-example.css'],
      templateUrl: 'input-overview-example.html',
    })
    export class InputOverviewExample implements OnInit, DoCheck {
      categories = [
        { id: 'id-1', name: 'Category 1' },
        { id: 'id-2', name: 'Category 2' },
        { id: 'id-3', name: 'Category 3' },
      ] as ExampleCategory[];
      item = new ExampleItem('Item One', this.categories[0].id);
      itemDiffer: KeyValueDiffer<string, any>;
    
      constructor(private readonly differs: KeyValueDiffers) { }
    
      ngOnInit() {
        this.itemDiffer = this.differs.find(this.item).create();
      }
    
      ngDoCheck(): void {
        const changes = this.itemDiffer.diff(this.item);
        if (changes) {
          //TODO: Save data here
          console.log("changed to: " + JSON.stringify(this.item));
        }
      }
    }
    
    export class ExampleItem {
      constructor(
        public name: string,
        public categoryId: string) {
      }
    }
    
    export class ExampleCategory {
      constructor(
        public id: string,
        public name: string) {
      }
    }
    

    还有组件HTML:

    <form>
        <mat-form-field class="col">
            <input matInput placeholder="Name" name="name" [(ngModel)]="item.name">
        </mat-form-field>
    
        <mat-form-field class="col">
            <mat-select placeholder="Category" name="category" [(ngModel)]="item.categoryId" required>
                <mat-option *ngFor="let category of categories" [value]="category.id">{{category.name}}</mat-option>
            </mat-select>
        </mat-form-field>
    </form>
    

    我希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      你仍然可以包装一个 &lt;form (change)="save()" [formGroup]="form"&gt;在它身边

      然后在您的其他垫子组件周围使用&lt;mat-form-field&gt;。它应该在表单组上收听。组件可以通过 formControlName=""

      获取标识符

      【讨论】:

      • 我更新了我的问题,我正在使用模板驱动的表单。
      猜你喜欢
      • 2021-12-13
      • 2021-10-31
      • 2020-10-29
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      相关资源
      最近更新 更多