JTangming / blog

My repository on GitHub.
Other
53 stars 0 forks source link

angular2 表单 #2

Open JTangming opened 8 years ago

JTangming commented 8 years ago

表单在我们的web应用中是至关重要的,表面上看,表单最直截了当的就是用户输入数据,点击提交这么简单。但事实上,表单所呈现的形式是非常复杂多变的,比如我们angular表单可以实现用户控制,监视变化,验证输入、错误信息处理和数据绑定等功能。

本节将详细介绍angular2表单,主要是从技巧方面来认识表单在angular2中带给用户的良好体验,具体如下:

angular2表单是基于HTML的模板及其控制该模板数据以及用户交互的组件组成,我们需要引入一个Componet,这意味着可以在该组件中定义选择器和模板或者引入一个外链的html模板。接下来定义一个组件类,其作用是控制表单相关属性的表现,定义表单方法等。

如下面的例子:【暂时用官网的例子。TODO...】

import {Compontent} from ‘angular2/core’;
import {NgForm} from ‘angular2/common’;
import {Hero} from ‘./hero’;
@Component ({
    selector: ‘hero-form’, 
    templateUrl: ‘app/hero-form.compontent.html
})
export class HeroFormCompent {
    powers = [‘ReallySmart’,’Super Flexible’,’Super Hot’,’Weather Changer’];
    model=new Hero(18,’DrIQ’,this.powers[0],’Chuck Overstreet’);
    submitted = false;
    onSubmitt(){this.submitted= true;}

在这个例子中,在引入的Component中,需要定义一个selector选择器,这表示我们能够在父模板中插入该表单。同样的,模板可以是外链URL模板也可以直接包裹在template键对应的值中。如:

template: `<form #f="ngForm" (submit)="search(f.value)">
            <select>
                <option value="web">网页</option>
                <option value="news">新闻</option>
                <option value="image">图片</option>
            </select>
            <input type="text" ngControl="kw">
            <button type="submit">搜索</button>
        </form>`

而控制表单的属性或者用户行为等,我们将定义一个类来处理,如HeroFormCompent类,我们定义了相关的属性,提交数据方法等。

2.表单指令

2.1 NgForm

NgForm指令为表单建立一个控件组对象,它包含当前选择器所在的form标签,关于NgForm请看下面的例子:

import {Component} from "angular2/core";
import {bootstrap} from "angular2/platform/browser";
import {CORE_DIRECTIVES,FORM_DIRECTIVES} from "angular2/common";

//组件
@Component({
    selector:"xx-app",
    directives:[FORM_DIRECTIVES,CORE_DIRECTIVES],
    template:`
        <form #f="ngForm"  
            <input type="text" ngControl="title">
            (ngSubmit)="onSubmit(f.value)"
        </form>
    `         
})
2.1.1 指令依赖声明

NgForm指令包含在预定义的数组变量FORM_DIRECTIVES中,所以我们要在组件注解的directives属性中优先声明FORM_DIRECTIVES,这样就可以直接使用NgForm指令了。

2.1.2 局部变量

通过使用“#”符号,我们可以创建一个引用控件组对象的局部变量,如上例中的变量f,这个变量它的value属性是一个JSON对象,该对象的键对应的是表单中input元素的ng-control属性,值对应的是input元素的值。接下来我们介绍NgControl。

2.2.NgControl

2.2.1 NgControl的运用

我们可以在input标签中添加ngControl属性,NgControl将创建一个新的Control并动态的将它添加到父ControlGroup中,同时绑定一个DOM元素到这个新的Control,这就将这个input标签和Control联系起来了,我们访问该标签将直接通过这个ngControl的属性值来访问。

需要注意的是,ngControl必须是作为一个NgForm或者NgFormModel的后代来使用,否则将会报错,因为这个指令需要将创建的控件对象添加到祖先(NgForm或者NgFormModel)所创建的控件中。

在这里,值得一提的是NgControlNmae,它的选择符是[ngControl],这就意味着,你必须和ngControl来搭配使用,这个指令才会发挥它的作用。NgControlName指令为宿主DOM对象创建一个控件对象,并将这个对象以ngControl属性指定的名称绑定到DOM对象上,举个例子,如我们最常用的用户名和密码表单:

<form #f="ngForm">
    <input class="user-name" type="text" ngControl="user">
    <input class="password" type="password" ngControl="password">
</form>

我们创建了两个Control对象,NgControlName指令为宿主DOM对象创建两个控件对象,然后将ngControl属性指定的名称user、password绑定到了其对应的input标签对应的DOM数上。这样的好处是我们可以很方便的通过控件组获取对应的值,也能实现ngModel模型与表单的双向绑定,下一节我们将介绍NgModel。

2.2.2 ngControl监视状态

表单不仅仅是数据的绑定,同样的,我们也希望能够监测到表单的状态,NgControl指令能够保持对状态的监视,除此之外,它会在这下面的三个状态值中影响着当前表单的控制器。

状态TrueFalse
control是否被访问 ng-touched ng-untouched
control是否发生了变化 ng-dirty ng-pristine
control是否合法有效 ng-valid ng-invalid

通过监测NgControl状态的改变,我们能设置我们想要的特殊css类来更新控制器,比如能够通过监视状态合法性的属性ng-valid和ng-invalid来改变控制器是否需要弹出或者显示输入非法的状态提醒,如显示、隐藏错误信息等。我们能瞬间探测到这些状态的改变,同时我们可以马上为我们的表单组件添加对应的处理。以下是对这些状态使用的一些例子:

// todo ...

2.3 NgModel

2.3.1 NgModel的运用

在表单中,我们常常需要用到这样的场景,在model数据结构有变化的时候,我们希望能够及时的反应在表单中,同样的,我们在操作表单的时候,也是需要表单的变化需要实时的在model中有响应的。也就是说,我们需要同一时间去显示、监听和摘录数据。

angular2采用的是ngModel来实现数据的双向绑定的,NgModel指令可以令表单和模型(model)的数据绑定超级简单,它的语法是:[(ngModel)]=“...”,例子如下。

<input type=”text” class=”form-controt” required [(ngModel)]=”model.name”>
TODO:监视这个表单的值:{{model.name}}
2.3.2 NgModel双向绑定原理

在模板语法里,我们已经了解过了属性绑定和事件绑定,在属性绑定里,值产生于模型赋值给目标属性,通过中括号-[]来包裹这个属性,那么我们的模型也将通过这个中括号内的属性值来辨识这个目标属性。这是一种由模型向视图的单项数据绑定。而事件绑定则相反,在事件绑定中,目标属性对应表单的变化的值将赋予给模型,通过小括号-()来包裹这个属性,这个包裹的属性将会标识模型中对应该目标属性名的变化。这是一种反向的视图向模型的单向数据绑定。这就是[()]实现数据双向绑定的方式,很好的预示将要发生什么。

如上面的例子,我们可以改写成这样:

<input type=”text” class=”form-control” required [ngModel]=”model.name” (ngModelChange)=”model.name=$event”>
TODO:监视这个表单的值: {{model.name}}

该表单中,模板表达式:model.name=$event是被用来发现来自于DOM事件的$event事件,ngModelChange不是一个input元素事件,本身不会产生一个DOM事件,实际上它是NgModel指令的一个事件属性,它是能够返回输入框的一种angular的EventEmitter属性,这种属性能够精确的捕获我们分配给模型“anyName”属性的值。在angular2表单中,我们看到[(anyName)]时,它预示着这个anyName指令将拥有一个该属性的输入值和一个对应着anyName-change的输出值。

2.4 NgSumit

用户填完表单之后,我们需要获取表单的完整数据以便提交。通常我们会在表单的底部添加一个提交按钮并设置其type的值等于submit,按钮本身不做任何事情但是却能监听表单的提交这个动作,但是此刻的提交没什么作用,为此,angular2提供了一个NgSubmit指令于form标签,这样我们就可以绑定事件到模型的submit方法上用来出来表单的提交了。例子如下:

import { Component } from 'angular2/core';  
import { FORM_DIRECTIVES } from 'angular2/common';

@Component({  
  selector: 'demo-form',  
  directives: [FORM_DIRECTIVES],  
  template: `   
    <form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
       <input type="text" ngControl="sku">  
       <button type="submit" class="button">Submit</button>  
    </form> 
  `
})  
export class DemoForm {  
  onSubmit(value: string): void {  
    console.log('you submitted value: ', value);  
  }
}

该例子中,我们定义了一个模板局部变量#f,并用NgForm指令来初始化它的值,这样我们就能通过submit来获取该表单需要提交的数据结构了。