Inside the parent component I have a child component. Both have their required fields. At the end I need the enable the submit button only if both components are valid (all their required fields are filled in this case).
How can I accomplish this, especially with template-driven validation?
Seed code
parent component
@Component({
selector: 'parent-comp',
templateUrl: 'parent.html'
})
export class Parent {
}
<input pInputText name="txt1" id="txt1"
required/>
<child-comp></child-comp>
<button pButton type="button" label="Submit"
[disabled]="IF ONE OF THE COMPS IS NOT VALID"></button>
child component
@Component({
selector: 'child-comp',
templateUrl: 'child.html'
})
export class Child {
}
<input pInputText name="txt2" id="txt2"
required/>
For validating both parent and child component, a single form need to be divided into multiple component.
Parent html
<form #parentForm="ngForm">
<input pInputText name="txt1" id="txt1"
required/>
<child-comp></child-comp>
<button pButton type="button" label="Submit"
[disabled]="!parentForm.valid"></button>
</form>
Parent Component
import { Component } from '@angular/core';
@Component({
selector: 'parent-comp',
templateUrl: 'parent.html'
})
export class Parent {
}
Child Form must not have form tag
<input pInputText name="txt2" id="txt2"
required/>
Child Component
import { Component } from '@angular/core';
import { ControlContainer, NgForm } from '@angular/forms';
@Component({
selector: 'child-comp',
templateUrl: 'child.html',
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
})
export class Child {
}
You can create @Output
variable in child that will emit form.valid value. You need to use FormBuilder
and FormGroup
(don't see it here).
Every time you change something inside form, you need to call a function that will emit onchange
.
Example for child:
@Output onchange: EventEmitter<Boolean> = new EventEmitter(false);
formInChild: FormGroup;
constructor(private fb: FormBuilder) {
this.formInChild = fb.group(...)
this.formInChild.valueChanges.subscribe(() => {
this.onchange.emit(this.form.valid);
}
}
Now in parent:
(view)
<child-comp (onchange)="setButtonState($event)"></child-comp>
<button pButton type="button" label="Submit"
[disabled]="!allvalid"></button>
(component)
formInParent: FormGroup;
allvalid: boolean = false;
constructor(private fb: FormBuilder) {
this.formInParent = fb.group(...);
}
setButtonState(formFromChildValid) {
this.allvalid = this.formInParent.valid && formFromChildValid;
}
In this case every time you change something in child's form, child's form valid state will be emitted to parent which will update allvalid
variable which is listened by button.