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.loged 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);
}
 
     
     
     
    