Reputation: 640
I want to disable a button on the parent form when the nested child form is invalid.
This is the parent form component:
<hello name="{{ name }}"></hello>
<h2>Complex form with address component</h2>
<form #myForm="ngForm">
<div>
<label>Firstname:</label>
<input type="text" name="firstName" ngModel>
</div>
<div>
<label>Lastname:</label>
<input type="text" name="lastName" ngModel>
</div>
<address></address>
</form>
<div>
Root group valid: {{ myForm.valid }}
</div>
<br>
<!-- I want to disable this button -->
<button [disabled]="!myForm.controls.address.valid">
Submit Address Only
</button>
This is the child address form component:
import { Component } from '@angular/core';
import { ControlContainer, NgForm } from '@angular/forms';
@Component({
selector: 'address',
template: `
<fieldset ngModelGroup="address" #group="ngModelGroup">
<div>
<label>Zip:</label>
<input type="text" name="zip" ngModel>
</div>
<div>
<label>Street:</label>
<input type="text" name="street" ngModel>
</div>
<div>
<label>City:</label>
<input type="text" name="city" ngModel required>
</div>
</fieldset>
Child group valid: {{ group.valid }}
`,
viewProviders: [ { provide: ControlContainer, useExisting: NgForm } ]
})
export class AddressComponent {}
I have attempted [disabled]="!myForm.controls.address.valid"
but get an error stating that address
is undefined
Here is a stackblitz https://stackblitz.com/edit/angular-jmdawu?file=app%2Fapp.component.html
Upvotes: 0
Views: 2210
Reputation: 57971
in this case the "simplest way" is to have a reference to the child using ViewChild
//in parent
@ViewChild(AddressComponent) addressComponent:AdressComponent
//or if you use in your .html a template reference
// see the "#addressRef"
// <address #addressRef></address>
@ViewChild("addressRef") addressComponent:AddressComponent
So, in parent you has access to all the variables and methods in child, so you can use in parent html
<button [disabled]="!addressComponent.group.valid?true:null">submit</button>
Upvotes: 0
Reputation:
You can work with the event emitter.
Child Component
TS
// your instance of the FormGroup
@ViewChild('group') group: FormGroup;
// emits the formGroup state to the parent
@Output() groupIsValid: EventEmitter<boolean> = new EventEmitter<boolean>();
ngOnInit() {
// subscribe to the state change event and emit the current state to the parent
this.group.statusChanges().subscribe(() => {
this.groupIsValid.emit(this.group.valid);
});
}
Parent Component
TS
Here we define a method that gets called when the event occures and a variable, that holds the state.
// initially set to false
childComponentIsValid: false;
// gets called by event emitter
onChildComponentEvent(value: boolean): void {
this.childComponentIsValid = value;
console.log('current child component validity state is: ' + this.childComponentIsValid);
}
HTML
Here we get the event from the child component by adding the parameter to the HTML-Tag
<address (groupIsValid)="onChildComponentEvent($event)"></address>
And here you use the variable.
<button [disabled]="!childComponentIsValid">
Submit Address Only
</button>
That's it.
Upvotes: 2