I have the following button in my template:
<button type="button" class="mgmButton" (click)="onSave()" [disabled]="saveDisabled()">Save</button>
The button is disabled based on the result of the saveDisabled function.
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;
}
An earlier version of the function didn't build the validationMessage, it just returned true or false. That worked w/o any errors. But when I added the validationMessage property to the method/component/template, I started getting the “expression has changed after it was checked” exception.
Based on other posts it looks like this occurs because I'm changing the validationMessage variable while change detection is still happening. I'm not sure I fully understand what's going on or the best way to get rid of the error.
Update:
I created a custom validator and it almost works perfectly.
My component has an array of data called tableData. Each row in tableData is an object that gets displayed as a row in an html table in the template. Sometimes a row is in a read-only mode, other times the data is in edit mode and so certain columns in the row are input fields, select drop-downs, etc.
The custom validator is applied to the form tag. It takes tableData as the input. All my validation logic works, and if the validator returns an error I display it in the template. (I did have to turn the tableData into a json string and then parse it to get the hand-off between component and validator to work correctly.)
But there seems to be an issue with the timing. Let's say that a given row is in edit mode and the user changes the value of a select menu. This select is bound to a property in one of the rows of tableData. The validation in the form is triggered, but the data passed in has the old value of the select, not the new one. In essence, the validation of the form happens before the data binding on a table row updates the backing object.
I solved by adding ChangeDetectionStrategy from angular core.
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'page1',
templateUrl: 'page1.html',
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With