Search code examples
angularangular2-formsangular6angular4-formsangular-validation

How to disable Parent Component Form Submit button if child component fields are not valid


I am using Template Driven Form.

Parent Component HTML

<form #BasicForm="ngForm" (ngSubmit)="onBasicDetailsSubmit()" id="BasicForm">

  <app-input-text [(sharedVar)]="dashboardDetails.Text1" [isMandatory]="true" ></app-input-text>
  <app-input-text [(sharedVar)]="dashboardDetails.Text2" [isMandatory]="false"></app-input-text>

  <input type="submit" value="Save" [disabled]="!BasicForm.valid" class="btn btn-success">

</form>

Child Component

TS

@Input() sharedVar: number;
@Input() isMandatory: boolean;

@Output() sharedVarChange = new EventEmitter();


change(newValue) {
  this.sharedVar = newValue;
  this.sharedVarChange.emit(newValue);
}

HTML

<input type="text" class="form-control" [(ngModel)]="sharedVar" (ngModelChange)="change($event)" [attr.required]="isMandatory">

The Submit button is not getting disabled. I have tried writing required in child component as well as parent component selector, but it doesn't work. Please help.


Solution

  • As you are using Template-Driven-Form, the best way to validate Child components is to create a custom-Directivelike this that you will always add in each field that you want to validate in the Child-Component-Form:

    You can use this one:

    import {Directive, OnInit} from '@angular/core';
    import {NgControl, NgForm, NgModel} from "@angular/forms";
    
    /**
     * This attribute directive must be used to each input-field of a childComponent.
     * That input-field must contain a NgModel attribute, else the application must throw an error
     * Usage: (<input class="form-control" type="text" registerChildComponentToForm
     *          [(ngModel)]="testname" name="testname" required />
     */
    
    @Directive({
        selector: '[registerChildComponentToForm]',
        providers: [NgModel]
    })
    export class RegisterTemplateFormModelDirective implements OnInit {
    
        constructor(private form: NgForm, private eltControl: NgControl) {
        }
    
        ngOnInit() {
            if (this.form && this.eltControl) {
                this.form.form.addControl(this.eltControl.name, this.eltControl.control);
            }
        }
    
    }

    Then register it into declarations and exports in your App-Module

    declarations: [
            RegisterTemplateFormModelDirective,
            ...
    ],
    exports: [
            RegisterTemplateFormModelDirective,
            ...
    ]

    Suppose that your <app-input-text> is this HTML code, then you should just use the directive(registerChildComponentToForm) like this:

    <input id="iban" name="iban" [(ngModel)]="bank.iban" #ibanRef="ngModel" 
      [required]="isMandatory" registerChildComponentToForm/>