2017年3月8日 星期三

[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




沒有留言:

張貼留言