2018-07-03---Angular2 Form表单(转载)

ng2的表单有三个重要概念

1 FormControl

它封装了表单的inputs项,对外暴露为一个可以操作的FormControl对象。

FormControl 和 FormGroup

1.1 FormControl 代表单一的 input 输入域,它是 angular2/forms 的最小单元,在 FormControl中我们可以访问 input的值,当前的状态,例如是否 valid,是否 dirty,是否有errors。 在组件中创建一个FormControl:

let name = nameControl.value; //kate

nameControl.errors //StringMap(string, any) of errors

nameControl.dirty //false

nameControl.valid </span>//true

于是创建表单的过程就是创建一系列FormControl并添加相应的元数据和逻辑代码的过程。在模板中这样使用一个FormControl:
<input type="text" [formControl]="name"> //form 表单中某一行
这时我们就相当于在表单form的上下文环境中创建了一个新的FormControl对象。由于大部分表单都不止一个输入域,因此,我们需要有一种方式来管理多个 FormControl,同时还需要验证我们的表单,我们可以使用循环来遍历所有的FormControl来实现,但是这样会相当笨重而且复杂,没事,ng2为我们提供了 FormGroup来解决这个问题,下面我们创建一个FormGroup:

name: new FormControl("issliu"),
job: new FormControl('web front end develpoer'),
zip: new FormControl("200000")})
</span>

在实现上,FormGroup和FormControl都继承自AbstractControl抽象类,这意味着只要是在AbstraclControl中拥有的属性和函数在这两者之间都可以使用。因此,我们同样可以查看FormGroup的状态,值,变化检测等等。

下面我们来创建一个表单:
在创建表单之前,我们需要引入相应的依赖:

import {FORM_DIRECTIVES} from '@angular/forms';
//FORM_DIRECTIVES 模块中包含了一系列常用的表单指令,只要我们在component的directives中引用了它,就可以在对应的template中使用这些指令
@Component({
    selector: "test-form",
    directives: [FORM_DIRECTIVES],
    template: `<form #f="ngForm" (ngSubmit)="onSubmit(f.value)"><input name="sku" placeholder="sku"></input><button type="submit">submit</button></form>`
})
export class DemoForm {
    onSubmit(form:any):void{
        console.log('form data:', form);
    }
}

这样,我们就实现了一个简单的表单。
详细解释:
这里可能会比较迷惑,因为我们并没有写什么指令在form上面,唯一的变化点在我们写了一个#f="ngForm"在form表单上面而已。
其实NgForm已经帮我们完成了这一切,在初始化Angular2表单时,只要我们引入了FORM_DIRECTIVES指令,它会自动检测form标签,如果form不包含
ngNoForm指令或者没有指定formGroup属性,则会自动为form表单应用NgForm指令,具体到细节就是绑定了一个名为ngForm的FormGroup到表单上。
这是一个非常有用的特性。当NgForm指令应用到form表单上后,它使得表单具有了以下两个功能:
(1) 一个名为 ngForm 的 FormGroup
(2) 表单具有一个 ngSubmit 的 @Output 属性
这里的#f="ngForm"表示我们使用了一个名为f的变量引用了这个表单对象,这样我们可以在模板的其他地方访问到它。
我们使用(ngSubmit)="onSubmit(f.value)"语句为表单绑定了一个提交行为,这个 onSubmit 方法是需要我们在对应的组件里面实现的。
这句话的意思是,当点击提交表单时,请调用组件的onSubmit方法。于是我们实现了一个具有一个input标签的可以提交的表单。

2 使用FormBuilder

ng2 为我们隐式构造FormControl 和 FormGroup 是非常简单快捷的。但是,如果我们希望自定义表单的行为怎么办?FormBuilder为我们很好的
解决了这个问题。

从命名上我们就可以看出,FormBuilder是用于帮助我们build表单的。前面我们提到表单是由FormControl和FormGroup组成的,这里我们可以把
FormBuilder理解为生产FormControl和FormGroup的工厂。
下面我们举例如何使用FormBuilder
我们需要引入REACTIVE_FORM_DIRECTIVE,这样才能在表单中使用formGroup和formControl指令。

import {FORM_DIRECTIVE, REACTIVE_FORM_DIRECTIVES,FormBuilder,FormGroup} from '@angular/form';
@Component({
    selector: "demo-form-builder",
    templateUrl:'demo.html',
    directives: [FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES]
})
export class DemoFormBuilder{
    myForm: FormGroup;
    constructor(private fb: FormBuilder) {
        this.myForm = fb.group({
            'sku': ['ABC123']
        })
    }
    onSubmit(value){
        console.log(value);
    }
}

这里我们在构造函数中注入了一个FormBuilder实例,这个FormBuilder实例具有两个主要的方法:
(1) fb.control() //构造一个FormControl实例
(2) fb.group() //构造一个FormGroup实例
上面的例子中,我们构造了一个名为myForm的FormGroup实例,这个group包含一个名为sku的control,默认值为'ABC123'.
现在我们把这个组件引用到模板中:

<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm.value)">
    <input [formControl]="myForm.controls['sku']"/>
    <button type="submit">submit</button>
</form>

这里,我们显示的指明了表单的formGroup属性,因此ng2不会为表单自动应用NgForm指令了。
NgForm自动应用的form表单需要符合以下规则:
form:not([ngNoForm]):not([formGroup]), ngForm, [ngForm]
这意味着使用了ngNoForm属性的表单也不会应用NgForm
总结:
如果我们需要隐式的创建FormGroup和FormControl,请使用 ngFrom和ngModel //FORM_DIRECTIVES
如果需要绑定到一个已经存在的FormGroup和FormControl对象,请使用formGroup和formControl //REACTIVE_FORM_DIRECTIVES

3 添加验证:

在上面的DemoFormBuilder 类构造函数中,我们为this.myForm初始化值,现在改为:

this.myForm = fb.group({
    'sku': ['', Validators.required]
})

我们已经可以在模板中通过myForm.controls['sku']来访问表单的sku值了,但是这样会在模板中写很多代码,最方便快捷的,是在组件内定义
一个实例变量用来引用名为sku的FormControl,例如

sku:AbstractControl;
this.sku = this.myForm.controls['sku'];

于是在模板中我们可以直接使用sku变量。这样做的好处,是在模板的任何一个地方我们都可以快速访问sku变量,但是如果是一个非常大的表单,
我们则需要在组件中初始化很多这样的变量,使得代码体验比较糟糕。
FormControl和FormGroup都具有hasError方法,
如果我们需要验证一个FormControl,可以这么写
<div *ngIf="sku.hasError('required')"></div>
如果需要验证FormGroup的某一项,那就这么写
<div *ngIf="myForm.hasError('required', 'sku')"></div>
现在,让我们来自定义一个Validator吧!

function skuValidator(control:FormControl): {[s:string]: boolean} {
  if(control.value.test(/^123/)) {
        return  {invalidSku: true}
      }
}

定义Validator有三个关键点:
它接受一个FormControl作为参数,同时返回一个StringMap<string, boolean>对象,如果这个boolean值为真表明验证通过,否则表明出错。
现在我们把这个验证项加入myForm:

    this.myForm = fb.Group({
        'sku': ['', Validator.compose([
            validators.required, skuValidator
        ])]
    })

ok,大功告成,现在我们在模板中可以使用:
<div *ngIf="myForm.hasError('skuValidator', 'sku')"></div>来检测是否通过Validator了
以上基本是angular表单中的主要功能,下面,我们还可以监听表单的变化:
同样,对于FormControl和FormGroup,都具有一个EventEmitter用来监听变动事件的。
我们通过调用control.valueChanges来获得他们的EventEmitter:

    this.sku.valueChanges.subscribe(
        (value: string) => {
            console.log("sku value changed", value)
        }
    )
    this.myForm.valueChanges.subscribe(
        (form: any) => {
            console.log("form chnged to:", form)
        }
    )
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容

  • 1.简单的H5表单 当我们点击注册按钮的时候会对表单进行校验 2.Angular表单的分类 两种表单的不同点 3....
    神豪VS勇士赢阅读 786评论 0 1
  • 版本:Angular 5.0.0-alpha 表单是商业应用的支柱,我们用它来执行登录、求助、下单、预订机票、安排...
    soojade阅读 1,276评论 0 1
  • 一阿姨牵着孙子,招孩子,径直蹒跚走来,躺式换坐式,孩子刹住小蹄子,双目发直,阿姨,帮腔,叫叔叔,叔叔酷不酷?不好意...
    纵情嬉戏天地间阅读 257评论 0 0
  • 和一个同样还没结婚的闺蜜聊天,说起有位好友比我小,但离婚两年,都要再婚了,我感叹道:“你说说,这日子真不禁过啊!”...
    小马不怕过河阅读 724评论 0 1
  • 我聞到星巴克的氤氲 淡淡地灑在陽光里 你喝過的那杯 余香未散 却被凝結成雪片 在心中零落飄散 那散落的碎片 成了傷...
    静观其然阅读 145评论 0 0