Reputation: 685
I have a situation where at first seemed fairly straight forward to myself but after a couple of days changing my solution structure it has become so convoluted! Well I have a got a parent/child component relationship as following:
Each of these components (parent, child and grand child) has a property as "isValid" and a "validate()" method. All I want to achieve is a solution in which each component validity state depends on its own validate logic PLUS validity of all children component. Here is a simple validation rules for each component:
I have already read this https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-on-changes and tried all possible ways it describes but neither fits my requirements of having the parent level component valid if ALL its children are valid!
thanks for your advice in advance :)
Upvotes: 1
Views: 3916
Reputation: 685
I have finally solved it by bind components together via a service. in the way that all validation logic is located in the service and all parent, children and grand children validation flags are bound to that service.
eg. in grand children:
this.subscription = this.validationService.onValidateEvent.subscribe(data => { this.isValid = this.validationService.validate(this.timeOfDay); });
Upvotes: 1
Reputation: 36
In the documentation you mention you can use parent-listens-for-child-event. In each child you will have an EventEmitter like so:
@Output() isValid = new EventEmitter<boolean>();
validate(valid: boolean) {
this.isValid.emit(valid);
}
that will be de-validated through a button for example:
<button (click)="validate(true)">Make child Valid</button>
The parent binds an event handler that responds to the child event payload $event and calculates its own validity:
children_valid:boolean[]; // for each parent children_valid.length==number_of_children
valid:boolen;
onValidate(valid: boolean, child_number: number) {
this.children_valid[child_number-1]=valid;
this.children_valid.some(x=>x==false) ? this.valid=false : this.valid=true
}
// Inside the template of the parent:
<my-child1
(onValidate)="onValidate($event,1)">
</my-child1>
<my-child2
(onValidate)="onValidate($event,2)">
</my-child2>
<my-child3
(onValidate)="onValidate($event,3)">
</my-child3>
If a component is a parent and a child it must emit and receive an event when something changes.
Upvotes: 0
Reputation: 3211
You didn't specify why the official documentation didn't help you..
Basically you need to follow the master/detail guide.
I guess I would have done it with couple of Boolean array's...
Last say 'parent' has an array of 2, representing it's two children.
So
parentValid:boolean[]=[false,false];
Every child has the same concept for it's children (Mark as grandchildren)
childValid:boolean[]=[false,false,false];
The grandchild should only have an emitter witch notify it's parent on valid change. On every event like that, update childValid
and do your logic there (More then 3 nor less then 1...) and emit the result to it's parent.
Upvotes: 0