Search code examples
angularangular7angular-formsangular-formbuilder

Perform form validation of nested form or nested form component in Angular 7?


I am using Angular 7 and Template Driven Forms. I have angular form in that form I'm calling another component (or Form) and there as well I have applied required and template driven validations.

Another form holds Department Name and which is mandatory while creating Student. When All the required fields have been populated then only I want to enable the save() button. But since department Name field is in different component, how will I check if that field is populated and now I should enable the button?

<div>
    <form novalidate #f=ngForm>
        <div style="position: relative;">
            <div class="awr-input">
                <label class="awr-inputbox-label">
                    Owner Name
                    <span class="awr-required">
                        <span aria-hidden="true">
                            *
                        </span>
                    </span>
                </label>
                <app-dept (selectedElement)=populateDepartment($event) [employeeName]=(student.studentName)></app-dept>
            </div>
        </div>
        .....
        .....
        .....
        <div class="fixed-bottom footer">
            <div class="awr-container">
                <div class="awr-row">
                    <div class="awr-col-12">
                        <div class="btn-group-2 float-right">
                            <div class="awr-cta float-right">
                                <div class="cta-with-icon">
                                    <button type="submit" class="awr-btn awr-btn-primary" title="Submit" aria-label="Save" (click)="saveStudent()" [disabled]="!f.form.valid">
                                        Save
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>    
    </form>
</div>

dept.component.html

<form novalidate #f1=ngForm>
    <div class="input-container">
        <input type="text" id="" class="input-box" aria-required="true" minlength="0" maxlength="100" autocomplete="off"
            width="0" min="" max="" step="" [(ngModel)]="inputField" name="inputField" (input)=getDept() required
            #deptName="ngModel">
    </div>

    <div class="input-flydown flydownStyle" *ngIf="deptList?.length > 0">
        <div>
            <dl *ngFor="let dept of deptList">
                <dt><a class="dxp-cta-link" (click)="sendDept(dept)">{{dept.name}}</a>
                </dt>
                <dd>{{dept.eId}} {{dept.jobTitle}}</dd>
            </dl>
        </div>
        <div *ngIf="deptName.invalid && (deptName.dirty || deptName.touched)" class="dxp-error dxp-required">
            Dept Name is mandatory.
        </div>
    </div>
</form>

Solution

  • Instead of having two different forms, just use nesting instead.

    Read more here, written by the awesome guru Alexey Zuev

    So basically just provide in child component:

    @Component({
      // ...
      viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
    })
    

    and in child template just remove the form tags. The parent will know about this child form and when the form controls in child are valid.

    DEMO with stripped version of your code: STACKBLITZ