Reputation: 5017
I have two buttons in the parent template. One button acts as the Submit for the parent/child form. The other should validate the child component form. Clicking the Submit button validates both - which is OK. However, I am not able to get the other button to validate my child component form. Essentially, show the required errors of Child form only when the "Check Phone" button is clicked.
Parent template:
<form id="sampleform" [formGroup]="sampleForm" (ngSubmit)="formsubmit()">
<mat-form-field>
<input matInput type="text" formControlName="name" [errorStateMatcher]="matcher">
<mat-error *ngIf="sampleForm.controls.name.hasError('required') && isShowErrors">This field is invalid</mat-error>
</mat-form-field>
<br/>
<br/>
<child-component [isShowErrors]="isShowErrors"></child-component>
</form>
<button type="button">Check phone</button> <br/>
<button type="submit" form="sampleForm" (click)="formsubmit()">Submit</button>
Parent Component TS:
export class AppComponent{
isShowErrors: boolean = false;
sampleForm: FormGroup;
matcher = new MyErrorStateMatcher();
constructor(private fb: FormBuilder){
}
ngOnInit(){
console.log(">>>>")
this.sampleForm = this.fb.group({
name: ['', Validators.required]
});
}
formsubmit(){
this.isShowErrors = true;
console.log(this.sampleForm);
if(this.sampleForm.valid){
//navigate
}
}
}
Child Component template:
<form [formGroup]="sampleChildForm">
<mat-form-field>
<input matInput type="text" formControlName="phone" [errorStateMatcher]="matcher">
<mat-error *ngIf="sampleChildForm.controls.phone.hasError('required') && isShowErrors">Test Error</mat-error>
</mat-form-field>
</form>
Stackblitz: https://stackblitz.com/edit/angular-gyzaag
Upvotes: 5
Views: 8147
Reputation: 56936
Here's a full working blitz ... https://stackblitz.com/edit/angular-7nbjnh ... that implements the solution given herein.
In child component controller add this method:
formsubmit(){
this.isShowErrors = true;
console.log(this.sampleChildForm);
if(this.sampleChildForm.valid){
//navigate
}
}
In parent component html change these lines:
<child-component #fred [isShowErrors]="isShowErrors"></child-component>
<button type="button" (click)="checkPhone()">Check phone</button>
In parent controller do this:
@ViewChild('fred') fred;
checkPhone() {
this.fred.formsubmit()
}
This basically allows the parent to call a method in the child. The key here is the #fred
reference variable. When you put a reference variable on an angular component it gives you access to the component class and its methods, so you can easily call child.formsubmit()
AKA fred.formsubmit()
from the parent.
Not relevant here but worthing knowing, when you put a reference variable on an HTML element it gives you access to the HTML element (in the same way that getElementById
does).
If interested, there is a newer slight variation of this approach which still uses @ViewChild
but does not require a reference variable here:
https://angular.io/guide/component-interaction#parent-calls-an-viewchild
This alternative approach is principally identical in that the parent still calls a method in the child. The hookup is just minimally different.
If you wish to use the alternative just drop the #fred
reference variable and do this for @ViewChild
in the parent controller:
import { ChildComponent } from './child/child.component';
@ViewChild(ChildComponent) private fred: ChildComponent;
I personally prefer use of the reference variable since it seems less tightly bound but I believe the latter approach is considered best practice since it is in the Angular docs under Component Interaction.
Upvotes: 3