8

I am trying to check the validity of a form placed on a child component from a parent component. The best scenario would be to disable a button on the parent component if the form is invalid or in the worse scenario to trigger an alert from the parent button if form is invalid.

I could achieve to check if the form has 'ng-invalid' class from the parent using a @ViewChild decorator to call a function on the child component as follows:

Parent Component:

export class CandidateVerificationComponent implements OnChanges, OnInit {

@ViewChild(RightPanelComponent) rightPanelPointer: RightPanelComponent;

saveAndFinish() {

    if (this.rightPanelPointer.checkFormValidity())
    {
        alert('No Valid');
        return;
    }

    this.rightPanelPointer.onSubmit();

  }    
}

Child Component:

export class RightPanelComponent implements OnChanges , OnInit{

@ViewChild("candiateForm", { read: ElementRef }) tref: ElementRef;

   checkFormValidity():boolean {        
    return (this.tref.nativeElement.className.indexOf('ng-invalid') !== -1);
   }  
}

It works for the worst scenario, but I do not like the idea to link the component to the DOM, I would rather a smarter idea.

I would like to use a template reference variable (#candiateForm), for example the one that allows to check validity in the submit button (see below) from the form (child) in order to check validity from the parent. Is it possible to have access to that template variable from the parent?

 <form (ngSubmit)="onSubmit()" #candiateForm="ngForm" name="candiateForm" (change)="formChanged()">
    <div class="form-group">
      <label class="control-label" for="firstName">First name:</label>                           
      <input type="text" class="form-control" id="firstName" pattern="^[^0-9]+$" required [(ngModel)]='candidate.firstName' name="firstName" #firstName="ngModel">
   </div>
<button type="submit" class="btn btn-default" [disabled]="!candiateForm.form.valid">Submit</button>
</form>
D.B
  • 4,009
  • 14
  • 46
  • 83

1 Answers1

18

Since Angular applies ngForm to all form elements implicitly and you can reference any component/directive in the component template by component/directive class reference, you don't have to read ElementRef and don't need the template reference #candiateForm, you can access the form directly by the directive class reference ngForm:

export class RightPanelComponent implements OnChanges , OnInit{
    @ViewChild(NgForm) form;

    checkFormValidity():boolean {        
        return this.form.valid;
    }

And also you can access the form directly from the parent component:

export class CandidateVerificationComponent implements OnChanges, OnInit {
    @ViewChild(RightPanelComponent) rightPanelPointer: RightPanelComponent;

    saveAndFinish() {
        if (this.rightPanelPointer.form.valid)
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • Ok, thanks, but the main problem is to access this.form.valid (child component) from the parent component. The @viewchild from the parent is what i am most interested about @ViewChild(RightPanelComponent) rightPanelPointer: RightPanelComponent; – D.B Jul 06 '17 at 08:56
  • This will work `rightPanelPointer.form.valid` in the parent component – Max Koretskyi Jul 06 '17 at 08:57
  • I have got: a property form doesn't exist on type RightPanelComponent , i do not know if it is because my form is a template-driven form placed into the html. – D.B Jul 06 '17 at 09:02
  • did you add `@ViewChild(NgForm) form;` to `RightPanelComponent `? – Max Koretskyi Jul 06 '17 at 09:03
  • add `import { NgForm } from '@angular/forms'` in the file with `RightPanelComponent ` – Max Koretskyi Jul 06 '17 at 09:09
  • Great. Yes, i can see it is valid or invalid. Is it possible to disable the button from the parent if invalid, i did something like that in the ngOnInit of the parent: this.isFormValid =this.rightPanelPointer.form.valid; then in the html but didnt work, it is undefined in there :( – D.B Jul 06 '17 at 09:15
  • that's probably a separate question, but because you wrote `[disabled]="!candiateForm.form.valid"` it will be tracking form status automatically. But you can also do it programatically from the form `this.form.controls[controlName].disable();` – Max Koretskyi Jul 06 '17 at 09:25
  • yes. that [disabled]="!candiateForm.form.valid" is in the submit button of the form, which I won't use to submit the form, i want to use the saveAndFinish from the parent, i showed the [disabled]="!candiateForm.form.valid" as an example of what i would like to achieve in the parent bottom. I will accept your answer and i will need to create another question one from this point. Thanks. – D.B Jul 06 '17 at 09:31
  • How can i detect changes in form state from parent component ? – Er Vipin Sharma May 29 '18 at 06:47
  • @ErVipinSharma, please ask another question – Max Koretskyi May 29 '18 at 11:39
  • 4
    what if you have multiple instances of RightPanelComponent? – james Jul 27 '18 at 04:50