Angular 具有材质组件的角度形状更改事件

Angular 具有材质组件的角度形状更改事件,angular,forms,angular-material,onchange,Angular,Forms,Angular Material,Onchange,我有一个表单,其中包含输入和材料组件(如mat select或mat checkbox) 每次用户进行修改时,我都希望将它们保存到数据库中。所以我做了一些类似于的事情 对于本机输入,这是完美的,但当用户更改材质组件值时,它不会触发 我宁愿避免在每个组件上使用这样的解决方案,因为当我不得不更新表单时,我很容易忘记添加它 编辑 这是一个模板驱动的表单。我的模板如下: <form (change)="save()"> <!-- Will trigger save -->

我有一个表单,其中包含输入材料组件(如
mat select
mat checkbox

每次用户进行修改时,我都希望将它们保存到数据库中。所以我做了一些类似于
的事情

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

我宁愿避免在每个组件上使用
这样的解决方案,因为当我不得不更新表单时,我很容易忘记添加它

编辑

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

<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>

你仍然可以包一个包
围绕它

然后在其他垫子组件周围使用
。它应该在formgroup上收听。组件可以使用formControlName=“”

获取标识器,您可以解决此问题

检查以下示例:

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) {
  }
}
import{Component,KeyValueChanges,keyvaluedifferent,keyvaluedifferent,DoCheck,OnInit}来自“@angular/core”;
@组成部分({
选择器:“输入概述示例”,
样式URL:['input-overview-example.css'],
templateUrl:'InputOverview example.html',
})
导出类InputOverview示例实现OnInit、DoCheck{
类别=[
{id:'id-1',名称:'Category 1'},
{id:'id-2',名称:'Category 2'},
{id:'id-3',名称:'Category 3'},
]例如,类别[];
item=新的ExampleItem('item One',this.categories[0].id);
ItemDifference:KeyValueDifferent;
构造函数(private readonly Differences:KeyValueDifferences){}
恩戈尼尼特(){
this.itemdifference=this.differences.find(this.item.create();
}
ngDoCheck():void{
const changes=this.itemdifference.diff(this.item);
如果(更改){
//TODO:在此处保存数据
log(“更改为:”+JSON.stringify(this.item));
}
}
}
导出类示例项{
建造师(
公共名称:string,
公共类别ID:字符串){
}
}
导出类示例类别{
建造师(
公共id: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>

{{category.name}

我希望这有帮助

此解决方案适用于角度11.2.1和材料11.2.1

您需要捕获可观察到的valueChanges变化

this.editForm.valueChanges
 .subscribe(value=> {
       if (this.editForm.dirty) {
              //do something
              }
           });
注意事项:

  • 通常情况下,如果(this.editForm.dirty){…},则不需要放置过滤器,因为正常行为是只有当该观察者发生更改(dirty)时,该观察者才应启动,但由于材质组件mat xxx,该观察者在字段值更改后几次启动,因此,为了避免对事件执行多次不必要的操作,如果(this.editForm.dirty){…}它只会在更改后执行,则必须根据此条件筛选可观察的对象

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

    能否显示您的组件代码?例如,您使用的是反应式/模板驱动的形式吗?@ DaiiLeRealyEvikBaunvo,我更新了我的问题。如果不需要模板驱动的窗体,那么您可以考虑转换为反应式。这将允许您在component.ts代码中订阅表单本身上的更改事件,而不是在HTML中使用一堆事件处理程序。如果您感兴趣,这里有一个文档链接。我并不认为使用反应式表单有什么好处,因为在我看来,它就像代码复制(因为我的模型对象已经存在)和SoC中的漏洞(因为后面的代码不应该知道模板上有什么)。我真的不理解这个问题,例如,mat select有一个双向绑定
    [()]
    ,因此应该触发更改事件,对吗?我更新了我的问题,我使用的是模板驱动的表单。