Wednesday, March 8, 2017

[Angular] Template-driven Forms with sub component

 Angular    Template-driven     Forms   Subcomponent  


▌Introduction


In this article, we will learn how to use sub-components in
Template-driven Forms.


▌Environment


▋Angular 2.4.0
▋Angular CLI 1.0.0-beta.31




▌Implement


Consider that we have a Form that will show different inputs when an option is changed.



Here we will use two components to display different inputs.


▋Main component

<!--<pre>{{form.value | json}}</pre>-->
<form novalidate #form="ngForm" (ngSubmit)="onSubmit(form)">
  <div class="form-horizontal">

    <div class="form-group required">
      <label class="control-label col-md-2">Product Type</label>
      <div class="col-md-3">

        <select class="form-control" required name="type" #type="ngModel" ngModel>
          <option *ngFor="let pt of productTypes" [ngValue]="pt">{{pt.name}}</option>
        </select>
      </div>
    </div>

    <cms-sub-list *ngIf="type.value?.id=='1'" [product]="prod" ></cms-sub-list>
    <cms-sub-detail *ngIf="type.value?.id=='2'" [product]="prod"></cms-sub-detail>

    <div class="form-group">
      <div class="col-md-offset-2 col-md-10">
        <input type="submit" value="Save" class="btn btn-success" [disabled]="form.invalid" /> &nbsp;
        <input type="button" value="Back" class="btn btn-warning" [routerLink]="['/Cms/Layout/Product/List']" />
      </div>
    </div>
  </div>
</form>



▋Sub component

Here is one of the sub-components.

<div class="form-group required">
  <label class="control-label col-md-2">Image</label>
  <div class="col-md-3">
    <input type="file" name="listPhoto">
  </div>
</div>

<div class="form-group required">
  <label class="control-label col-md-2">Banner</label>
  <div class="col-md-3">
    <input type="file" name="ListPhoto">
  </div>
</div>

<div class="form-group required">
  <label class="control-label col-md-2">Template</label>
  <div class="col-md-3">
    <input type="radio" value="list" checked="checked" name="template" #template="ngModel" [(ngModel)]="prod.template">
    <img src="assets/images/prod_template_1.png" width="300px" align="top" class="preview"> &nbsp;&nbsp;&nbsp;&nbsp;
  <input type="radio" value="detail" name="template" #template="ngModel" [(ngModel)]="prod.template">
  <img src="assets/images/prod_template_2.png" width="300px" align="top" class="preview">
  </div>
</div>

<div class="form-group required">
  <label class="control-label col-md-2">Name</label>
  <div class="col-md-3">
    <input type="text" class="form-control" required name="title" #title="ngModel" [(ngModel)]="prod.title" />
  </div>
</div>

<div class="form-group required">
  <label class="control-label col-md-2">Publish date</label>
  <div class="col-md-3">
    <input type="text" class="form-control" required name="publishDate" #publishDate="ngModel" [(ngModel)]="prod.publishDate" />
  </div>
</div>

<div class="form-group required">
  <label class="control-label col-md-2">Remove date</label>
  <div class="col-md-3">
    <input type="text" class="form-control" required name="downDate" #downDate="ngModel" [(ngModel)]="prod.downDate" />
  </div>
</div>

<div class="form-group required">
  <label class="control-label col-md-2">Description</label>
  <div class="col-md-3">
    <textarea required name="description" #description="ngModel" [(ngModel)]="prod.description"></textarea>
  </div>
</div>






▋The problem

Now we have a problem that the form value only contains the parent component’s NgModels but without subcomponent’s.

The form.value is shown below.
 




▋How to solve the problem

We have to add the subcomponent’s NgModels to the parent component’s NgForm.

▋ Sub-component


import { NgForm, NgModel } from '@angular/forms';
import { Component, OnInit, Input, ViewChildren, QueryList } from '@angular/core';
@Component({
  selector: 'cms-sub-list',
  templateUrl: './sub-list.component.html'
})
export class SubListComponent implements OnInit {
  @ViewChildren(NgModel) controls: QueryList<NgModel>;
  @Input('product') prod: Product;

  constructor(private parentForm: NgForm) { }

  ngOnInit() {
  }

   ngAfterViewInit() {
    this.controls.forEach((control: NgModel) => {
      this.parentForm.addControl(control);
    });
   }
}



u  We use ViewChildren to get all the NgModels.
u  Inject the parent component’s NgForm.


And finally we could get the correct NgForm in parent component.





▌Reference




No comments:

Post a Comment