2017年3月8日 星期三

[Angular] Template-driven Forms

 Angular    Template-driven     Forms  


Introduction


We will practice
Template-driven Forms which contains textbox, radio buttons, checkbox and drop-down list.


Environment

Angular 2.4.0
Angular CLI 1.0.0-beta.31




Implement


The expected layout should be looked like this.
We will create each Html element one by one.



Form

<form novalidate #form="ngForm" (ngSubmit)="onSubmit(form)">

</form>

u  novalidate :Disable the validation when the form is submit.
u  Set a variable syntax #form to ngForm, so that we can use ngForm in the template.
u  Set event binding (ngSubmit) and reference to function onSubmit with parameter form => ngForm


Radio Buttons

HTML

  <div class="form-horizontal">
    <div class="form-group required">
      <label class="control-label col-md-2">State</label>
      <div class="col-md-3">
        <input type="radio" value="enabled"  name="status" #status="ngModel" [(ngModel)]="defaultStatus"> Enable &nbsp;&nbsp;&nbsp;&nbsp;
        <input type="radio" value="disabled" name="status" #status="ngModel" [(ngModel)]="defaultStatus"> Disable
      </div>
    </div>
</div>

u  name is a must!
u  Set the value for the checkboxes
u  Set variable syntax #status to ngModel for later usage.
u  If we DO NOT need to set the default checked/unchecked, then just put ngModel to the element like this,

<input type="radio" value="disabled" name="status" #status="ngModel" ngModel/>

But in this sample, we would like to set the default checked/unchecked value to them, so we use the two-way binding to ngModel.

Component

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-account-create',
  templateUrl: './account-create.component.html'
})
export class AccountCreateComponent implements OnInit {
  private defaultStatus: string;
  ngOnInit() {
    this.defaultStatus = "enabled";
  }

  //Sdubmit
  private onSubmit(form: NgForm) {
    
  }
}

TIP :

We can use <pre>{{form.value | json}}</pre>  to make sure that the ngForm has the correct data.




Textbox

  <div class="form-horizontal">
    <div class="form-group required">
      <label class="control-label col-md-2">ID</label>
      <div class="col-md-3" [ngClass]="{'has-error': id.invalid && id.dirty}">
        <input type="text" class="form-control" required name="id" #id="ngModel" ngModel /
      </div>
    </div>
</div>

ID is a required input, so we add required on the element and use #id (NgModel) to check invalid and dirty value and set the ngClass.





Here are some useful properties of NgModel.

<pre>dirty : {{id.dirty}}</pre>
    <pre>disabled : {{id.disabled}}</pre>
    <pre>enabled : {{id.enabled}}</pre>
    <pre>errors : {{id.errors | json}}</pre>
    <pre>invalid : {{id.invalid}}</pre>
    <pre>name : {{id.name}}</pre>
    <pre>pristine : {{id.pristine}}</pre>
    <pre>touched : {{id.touched}}</pre>
    <pre>untouched : {{id.untouched}}</pre>
    <pre>valid : {{id.valid}}</pre>
    <pre>value : {{id.value}}</pre>





Textbox with complicated validation

We will validate that the “Password” and “Confirm Password” should be the same, or show an alert message.

 <div class="form-group required">
      <label class="control-label col-md-2">Password</label>
      <div class="col-md-3" [ngClass]="{'has-error': password.invalid && password.dirty}">
        <input type="password" class="form-control" required name="password" #password="ngModel" ngModel />
        <span class="label label-danger" *ngIf="password.dirty && password.value!=confirmPassword.value">Password not match!</span>
      </div>
    </div>

    <div class="form-group required">
      <label class="control-label col-md-2">Confirm Password</label>
      <div class="col-md-3" [ngClass]="{'has-error': confirmPassword.invalid && confirmPassword.dirty}">
        <input type="password" class="form-control" required name="confirmPassword" #confirmPassword="ngModel" ngModel />
        <span class="label label-danger" *ngIf="confirmPassword.dirty && password.value!=confirmPassword.value">Password not match!</span>
      </div>
    </div>






Drop-down list

Refer to my previous article:
[Angular2] dropdown list with ngFor and enum

Just add the name, ngModel on <select>.

HTML

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

        <select class="form-control" name="department" #department="ngModel" ngModel>
          <option *ngFor="let dept of departmentList" [ngValue]="dept">{{dept.name}}</option>
        </select>
      </div>
    </div>


Component

 constructor(private deptSvc: DepartmentService) {
  }

  ngOnInit() {

    //...

    this.deptSvc.getAll().subscribe(data => {
      this.departmentList = data;
    });
  }





Checkbox


<div class="form-group required">
      <label class="control-label col-md-2">Account Role</label>
      <div class="col-md-3">
        <input type="checkbox" name="isManager" ngModel> Admin
        <input type="checkbox" name="isReviewer" ngModel> Review
        <input type="checkbox" name="isDeleter" ngModel> Delete
      </div>
    </div>






Submit and cancel buttons


Here we can use form.invalid to disable or enable the Submit button.

<input type="submit" value="Save" class="btn btn-success" [disabled]="form.invalid" />
<input type="button" value="Back" class="btn btn-warning" [routerLink]="['/Cms/Layout/Account/List']" />



Submit!

Let’s first create the classes for the data from the Form.


account.ts

import { Department } from './department';
import { Role } from './role';

export class Account {
  id: string;
  password: string;
  confirmPassword: string;
  name: string;
  email: string;
  status: string;
  department: Department;
  jobTitle: string;
  isManager: boolean;
  isReviewer: boolean;
  isDeleter: boolean;

  public constructor(
    fields?: {
      id?: string;
      password?: string;
      confirmPassword?: string;
      name?: string;
      email?:string;
      status?: string;
      department?: number;
      jobTitle?: string;
      isManager?: boolean;
      isReviewer?: boolean;
      isDeleter?: boolean;
    }) {
    if (fields) {
      Object.assign(this, fields);
    }
    else {
      this.isManager = false;
      this.isReviewer = false;
      this.isDeleter = false;
      this.department= new Department();
    }
  }
}

account.ts

export class Department {
  id: string;
  name: string;
}



role.ts

export class Role {
  name: string
}



At last, we could complete the submit function J

 private onSubmit(form: NgForm) {
    let act: Account = null;
    if (form && form.value) {
      act = form.value;
      //Post it to backend....
    }
  }


Demo





Summary


From the tutorial, we found that Angular Template-driven Forms are really easy and quick to implement. However, if we want to create a dynamic form, using Model-driven Forms will be more suitable and flexible. We will talk about it in the next article.


Reference




沒有留言:

張貼留言