我的模板中有以下按钮:
<button type="button" class="mgmButton" (click)="onSave()" [disabled]="saveDisabled()">Save</button>
根据saveDisabled函数的结果,该按钮被禁用。
saveDisabled(): boolean {
this.validationMessage = '';
for (var i = 0; i < this.tableData.length; i++) {
let row = this.tableData[i];
if (row.edit) {
if (row.data.roleCode == null || row.data.roleCode == '' ||
row.data.grantProgramCode == null || row.data.grantProgramCode == '') {
this.validationMessage = 'Row ' + (i + 1) + ' has not filled in all required fields. ';
}
}
}
if(this.validationMessage == '') {
return false;
} else {
return true;
}
该函数的较早版本没有构建validationMessage,它只是返回true或false。没有任何错误的工作。但是,当我将validationMessage属性添加到方法/组件/模板时,我开始出现“检查后表达式已更改”异常。
根据其他帖子,这似乎是由于我在更改检测仍在进行时更改了validationMessage变量而发生的。我不确定我是否完全了解发生了什么或摆脱错误的最佳方法。
更新:
我创建了一个自定义验证器,它几乎可以完美运行。
我的组件有一个名为tableData的数据数组。 tableData中的每一行都是一个对象,该对象在模板的html表中显示为一行。有时一行处于只读模式,有时数据处于编辑模式,因此该行中的某些列是输入字段,选择下拉列表等。
自定义验证器将应用于表单标签。它以tableData作为输入。我所有的验证逻辑均有效,并且如果验证器返回错误,则将其显示在模板中。 (我确实必须将tableData转换为一个json字符串,然后对其进行解析,以使组件和验证程序之间的交接正常工作。)
但是时间似乎有问题。假设给定的行处于编辑模式,并且用户更改了选择菜单的值。此选择绑定(bind)到tableData的一行之一中的属性。表单中的验证被触发,但是传入的数据具有选择的旧值,而不是新的值。本质上,在表格行上的数据绑定(bind)更新支持对象之前,将进行表单的验证。
最佳答案
@Vilmantas正确描述了正在发生的事情。他没有说的是这种方法通常是不正确的。否则,应该根据更改检测甚至开始之前已经计算出的有效性标志来计算禁用标志,而不是同时进行。
Angular 2提供了专门用于此任务的特殊验证机制:接口(interface)Validator,您可以在自定义指令中实现该接口(interface),并且该指令可以将自身提供为NG_VALIDATORS token 的多提供者。以下是我的一个项目的示例。
同样,验证器可以是异步的(NG_ASYNC_VALIDATORS token 的提供者),这也是内置选项。在这种情况下,您可以考虑使用“pending”标志来绘制一些待验证的指示符,例如通过调用某些Web服务来检查用户名的可用性。
将验证器提供给ngModel之后,您可以使用带有值的标准ngModel.errors映射或ngModel.valid标志(以及其他标志-也有很多标志)来确定是否存在任何错误并基于启用/禁用控件在上面。使用这种方法,您甚至不需要考虑何时执行-angular会为您处理所有事情。
当然,您必须对它进行组织,以便它可以在模板上下文中使用,我的意思是正确导入/导出某些模块/组件以及此类内容。
import {Directive, forwardRef} from '@angular/core';
import {Validator, AbstractControl, NG_VALIDATORS} from '@angular/forms';
import {IDateValidationResult} from './date-validator.interfaces';
import {moment} from '../../../shared/moment';
const DATE_VALIDATOR = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => DateValidatorDirective),
multi: true
};
@Directive({
selector:
'[whatever-selector-you-want]',
providers: [DATE_VALIDATOR]
})
export class DateValidatorDirective implements Validator {
validate = (control: AbstractControl): IDateValidationResult => {
if (!control) {
return {required: true};
}
if (control.value === undefined) {
return {required: true};
}
if (control.value === null) {
return {invalidFormat: true};
}
let m = moment(control.value);
if (!m.isValid()) {
return {invalidFormat: true};
}
return null;
}
}
模板:
<input type="date" [(ngModel)]="myModel" whatever-selector-you-want #myDateCtrl="ngModel">
<div *ngIf="myDateCtrl.invalid">
<div *ngIf="myDateCtrl.errors.required">The date is required</div>
<div *ngIf="myDateCtrl.errors.invalidFormat">Date format is invalid</div>
</div>
关于angular - Angular2 “expression has changed after it was checked”异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42120811/