Angular 个具有 material 个组件的表单更改事件
Angular form change event with material components
我有一个包含 输入 和 material 组件 的表单(如 mat-select
或 mat-checkbox
).
每次用户进行修改时,我都想将它们持久化到数据库中。所以我做了类似 <form (change)="save()">
.
的事情
这对于本机输入来说是完美的,但当用户更改 material 组件值时它不会触发。
我宁愿避免在每个组件上使用 <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;
)。
你仍然可以包装一个
<form (change)="save()" [formGroup]="form">
周围
然后在其他垫子组件周围使用 <mat-form-field>
。它应该在表单组上收听。组件可以使用 formControlName=""
获取标识符
使用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>
希望对您有所帮助!
此解决方案适用于 Angular 11.2.1 和 Material 11.2.1
您需要使用 valueChanges observable 捕获更改
this.editForm.valueChanges
.subscribe(value=> {
if (this.editForm.dirty) {
//do something
}
});
注意事项:
- 通常你不需要放置过滤器 if(this.editForm.dirty) {...} ,因为正常行为是这个观察者只有在它被改变(脏)时才应该启动,但是由于对于 material 组件 mat-xxx,这个观察者在字段的值改变后被踢了几次,所以为了避免多次不必要地执行事件,你必须通过这个条件过滤观察者 if (this.editForm.dirty) {...} 它只会在更改后执行。
这同样适用于响应式表单,我刚刚注意到您的问题使用了模板驱动,但值得注意以防万一有人正在寻找响应式表单的解决方案。
我有一个包含 输入 和 material 组件 的表单(如 mat-select
或 mat-checkbox
).
每次用户进行修改时,我都想将它们持久化到数据库中。所以我做了类似 <form (change)="save()">
.
这对于本机输入来说是完美的,但当用户更改 material 组件值时它不会触发。
我宁愿避免在每个组件上使用 <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;
)。
你仍然可以包装一个
<form (change)="save()" [formGroup]="form">
周围
然后在其他垫子组件周围使用 <mat-form-field>
。它应该在表单组上收听。组件可以使用 formControlName=""
使用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>
希望对您有所帮助!
此解决方案适用于 Angular 11.2.1 和 Material 11.2.1
您需要使用 valueChanges observable 捕获更改
this.editForm.valueChanges
.subscribe(value=> {
if (this.editForm.dirty) {
//do something
}
});
注意事项:
- 通常你不需要放置过滤器 if(this.editForm.dirty) {...} ,因为正常行为是这个观察者只有在它被改变(脏)时才应该启动,但是由于对于 material 组件 mat-xxx,这个观察者在字段的值改变后被踢了几次,所以为了避免多次不必要地执行事件,你必须通过这个条件过滤观察者 if (this.editForm.dirty) {...} 它只会在更改后执行。
这同样适用于响应式表单,我刚刚注意到您的问题使用了模板驱动,但值得注意以防万一有人正在寻找响应式表单的解决方案。