Angular Form validation on child components

Guido Neele picture Guido Neele · Jul 25, 2017 · Viewed 14.1k times · Source

I've written a dynamic form in which there is a main part and sub parts based on a type that's selected in the main part (widget.type). Showing and hiding the sub parts is done with an ngSwitch.

HTML of the form looks like this:

<form class="widget-form cc-form" (ngSubmit)="saveChanges()" novalidate>
  <div class="forms-group">
    <label for="title" i18n="@@title">Titel</label>
    <input class="form-control" id="title" name="title" type="text" [(ngModel)]="widget.title" required />
  </div>

  <div class="forms-group">
    <label class="checkbox-label" for="show" i18n>
      <input id="show" name="show" type="checkbox" [(ngModel)]="widget.show" /> <span>Titel tonen in app</span>
    </label>
  </div>

  <div class="forms-group">
    <label for="type" i18n="@@type">Type</label>
    <select class="form-control" id="type" name="type" [(ngModel)]="widget.type" required>
      <option value="text-widget" i18n="@@Text">Tekst</option>
      <option value="tasklist-widget" i18n="@@Tasklists">Takenlijst</option>      
      <option value="image-widget" i18n="@@Text">Afbeelding(en)</option>
      <option value="video-widget" i18n="@@Video">Youtube</option>
      <option value="link-widget" i18n="@@Link">Link</option>
      <option value="contacts-widget" i18n="@@Contacts">Contactpersonen</option>
      <option value="attachment-widget" i18n="@@Attachments">Bijlage(n)</option>
    </select>
  </div>

  <ng-container [ngSwitch]="widget.type">

    <text-widget *ngSwitchCase="'text-widget'" [data]="widget"></text-widget>

    <tasklist-widget *ngSwitchCase="'tasklist-widget'" [data]="widget"></tasklist-widget>

    <image-widget *ngSwitchCase="'image-widget'" [data]="widget"></image-widget>

    <video-widget *ngSwitchCase="'video-widget'" [data]="widget"></video-widget>

    <link-widget *ngSwitchCase="'link-widget'" [data]="widget"></link-widget>

    <contacts-widget *ngSwitchCase="'contacts-widget'" [data]="widget"></contacts-widget>

    <attachment-widget *ngSwitchCase="'attachment-widget'" [data]="widget"></attachment-widget>

  </ng-container>

</form>

Every widget is it's own component.

The problem is that the form validation only checks the inputs from the main part and disregards the sub part (widget components). How can I make sure the input fields from the widgets are included in the validation?

I tried adding an isValid() method to the widget components but I couldn't get the instances of the components, probably because they are used in an ngSwitch. @ContentChild, @ContentChildren, @ViewChild etc. all returned undefined.

Answer

Lazy Coder picture Lazy Coder · Sep 9, 2019

For future googlers,

I had a similar issue to this, albeit with fewer child components and after digging through @penleychan's aforementioned thread on the subject I found a little gem that solved this for me without the need to implement a custom directive.

import { ControlContainer, NgForm } from '@angular/forms';

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

This works for my nested form. Just needs to be added to components, which ones directly contains inputs

https://github.com/angular/angular/issues/9600#issuecomment-522898551