I have created a custom component that contains a form <address></address>
. And I have a parent component that has an array of these:
@ViewChildren(AddressComponent) addressComponents: QueryList<AddressComponent>;
So the parent can contain a collection of these elements and the user can add and remove them based on the number of addresses they will be entering.
The parent also has a button to proceed after the user has entered all desired addresses. However, the <address>
component must be filled out correctly so I have a public getter on the <address>
component:
get valid(): boolen {
return this._form.valid;
}
Back to the button on the parent. It needs to be disabled if any of the <address>
components are invalid. So I wrote the following:
get allValid() {
return this.addressComponents && this.addressComponents.toArray().every(component => component.valid);
}
And in the parent template:
<button [disabled]="!allValid" (click)="nextPage()">Proceed</button>
But angular doesn't like this because addressComponents
are not defined in the parent until ngAfterViewInit
lifecycle event. And since it immediately runs ngOnViewInit()
I get two different values for the expression check which causes the error. (At least that's what I think is going on).
How do I use a property in my template that depends on ngAfterViewInit
? Or what is the best way to inform my parent that all of its children are valid?
The Error Message:
Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'
Update:
So I console.log
ed the return value of allValid
and noticed the first time it was undefined
. This was to be expected as this.addressComponents
are undefined
until ngAfterInit
. The next log it was true
and this was surprising as I didn't have any <address>
components on the page (yet). I am using mock data (all valid, though) in ngOnInit
of the parent component to create a component. I did learn that ([].every...
returns true on an empty array). So the third call to the console.log
was returning false
. Again, I am a little surprised because all my data is valid. On the 4th log it was returning true
which is what I expected. So I'm assuming this final value being returned is what Angular disliked.
Anyway, I was able to sort of solve this. I don't know if I'm actually fixing the problem or just suppressing the error. I do not like this solution so I am going to keep the question open for a better solution.
get allValid() {
return this.addressComponents && this.addressComponents.length > 0 && this.addressComponents().toArray().every(component => component.valid);
}