angular4 (5)表单处理

<1>angular表单API

40.png

不同点

41.png

注意
要使用angular表单,要在app.module.ts中引入相应的模块
模版式表单:FormsModule
响应式表单:ReactiveFormsModule

42.png

<2>模版式表单

使用模版式表单时,只能使用指令来定义数据模型。

(1)NgForm

用来代表整个表单,在angular项目中,它会自动添加到每个form标签上。
示例:
1.新建一个组件

ng g component templateForm

2.修改template-form.component.html

<form action="/action" method="POST">
  <p>用户名:<input type="text"></p>
  <p>手机号:<input type="text"></p>
  <p>密码:<input type="password"></p>
  <p>确认密码:<input type="password"></p>
  <button type="submit">提交</button>
</form>

3.修改app.component.html

<app-template-form></app-template-form>

4.修改app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TemplateFormComponent } from './template-form/template-form.component';
import { NgModule } from '@angular/core';

// 引入
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    TemplateFormComponent
  ],
  imports: [
    BrowserModule,
    // 添加
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

5.界面

43.png

在非angular接管的表单中,点击提交,url会变成:localhost:4200/action,
而angular接管的表单中,点击提交url不会有变化。
若想要指定form不被angular接管,可以定义:

<!-- 添加ngNoForm表示此表达不让angular接管 -->
<form action="/action" method="POST" ngNoForm>
  <p>用户名:<input type="text"></p>
  <p>手机号:<input type="text"></p>
  <p>密码:<input type="password"></p>
  <p>确认密码:<input type="password"></p>
  <button type="submit">提交</button>
</form>

特性:ngForm指令可以被一个模版本地变量引用,以便在模版中访问ngForm对象的实例。
例子:
1.修改template-form.component.html

<!-- 声明一个模板变量#myForm -->
<form #myForm=ngForm action="/action" method="POST">
  <p>用户名:<input type="text"></p>
  <p>手机号:<input type="text"></p>
  <p>密码:<input type="password"></p>
  <p>确认密码:<input type="password"></p>
  <button type="submit">提交</button>
</form>
<!-- 下面通过这个模板变量来访问ngForm对象的属性 -->
<!-- value是一个js对象,它保存了当前表单里面的值 -->
{{myForm.value | json}}

2.结果

44.png

(2)NgModel

ngModel指令代表表单中的一个字段,这个指令会隐式的创建一个FormControl的实例,来代表字段的数据模型,并用这个FormControl类型的对象来存储字段的值。
在上面例子的json中,当在表单中输入值时没有加到json中显示的原因是,那些input标签并未绑定ngModel指令。
注意
在ngForm中使用ngModel不需要像普通的数据双向绑定那样用[(ngModel)]的方式,直接写ngModel即可
ngModel也可以使用模版变量来获取它的值
示例
1.

<!-- 声明一个模板变量#myForm -->
<form #myForm="ngForm" action="/action" method="POST">
  <!-- 给用户名绑定ngModel,并且声明一个模板变量#user -->
  <!-- 注意,一定要给标签声明一个name属性 -->
  <p>用户名:<input #user="ngModel" ngModel name="username" type="text"></p>
  <p>手机号:<input type="text"></p>
  <p>密码:<input type="password"></p>
  <p>确认密码:<input type="password"></p>
  <button type="submit">提交</button>
</form>
<!-- 下面通过这个模板变量来访问ngForm对象的属性 -->
<!-- value是一个js对象,它保存了当前表单里面的值 -->
{{myForm.value | json}}

<!-- 用#user模板变量来获取用户名的值 -->
{{username.value}}

2.结果
此时再次输入用户名时就会实时反映到下面的json中

45.png

当应用为单页应用并不需要跳转网页时,往往用ngSubmit来替代form标签的提交作用
示例
1.修改template-form.component.html

<!-- 绑定ngSubmit,并定义一个方法fun,传入myForm的值到后台 -->
<form #myForm="ngForm" (ngSubmit)="fun(myForm.value)" action="/action" method="POST">
  <p>用户名:<input #user="ngModel" ngModel name="username" type="text"></p>
  <p>手机号:<input type="text"></p>
  <p>密码:<input type="password"></p>
  <p>确认密码:<input type="password"></p>
  <button type="submit">提交</button>
</form>
{{myForm.value | json}}
{{username.value}}

2.修改template-form.component.spec.ts

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

@Component({
  selector: 'app-template-form',
  templateUrl: './template-form.component.html',
  styleUrls: ['./template-form.component.css']
})
export class TemplateFormComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }
  onSubmit(value:any) {
    console.log(value);
  }
}

(3)NgModelGroup

代表的是表单的一部分,它允许你将一些表单字段组织在一起,形成一个更清晰的层次关系,与ngForm指令类似,ngModelGroup指令也会创建一个FormGroup类的一个实例,这个实例会在ngForm对象的value属性中表现为一个嵌套的对象,所以说ngModelGroup的子属性都会变为这个嵌套对象的子属性
示例
1.修改template-form.component.html

<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)">
  <!-- 嵌套一个ngModelGroup -->
  <div ngModelGroup="userInfo">
    <p>用户名:<input #user="ngModel" ngModel name="username" type="text"></p>
    <p>手机号:<input type="text"></p>
  </div>
  <p>密码:<input type="password"></p>
  <p>确认密码:<input type="password"></p>
  <button type="submit">提交</button>
</form>
<!-- 下面通过这个模板变量来访问ngForm对象的属性 -->
<!-- value是一个js对象,它保存了当前表单里面的值 -->
{{myForm.value | json}}

<!-- 用#user模板变量来获取用户名的值 -->
{{username.value}}

2.结果
username就被嵌套在userInfo中成为了userInfo的一个属性。

46.png

(4)重构用户注册表单的案例

1.修改template-form.component.html

<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)">
  <div ngModelGroup="userInfo">
    <p>用户名:<input #user="ngModel" ngModel name="username" type="text"></p>
    <p>手机号:<input ngModel name="phone" type="text"></p>
  </div>
  <!-- 嵌套一个ngModelGroup -->
  <div ngModelGroup="passwordsGroup">
    <p>密码:<input ngModel name="password" type="password"></p>
    <p>确认密码:<input ngModel name="pconfirm" type="password"></p>
  </div>
  <button type="submit">提交</button>
</form>

2.结果
当输入结束,点击提交时

47.png

<3>响应式表单

与模版式表单不同,创建一个响应式表单需要两步,首先需要编码来创建一个数据模型,然后需要使用些指令将模版中的html元素连接到这个数据模型上。

1、数据模型

是指用来保存表单数据的数据结构,简称模型。它由定义在angular的forms模块中的三个类组成。分别是:FormCotrol,FormGroup,FormArray

(1)FormCotrol:是构成表单的基本单位,通常情况下它用来代表一个input元素,它也可以用来代表一个更复杂的UI组件,比如说日历、下拉选择块等。FormCotrol保存着与其关联的html元素当前的值以及元素的校验状态,还有元素是否被修改过等信息。

如何创建一个FormCotrol,示例:

//其中FormCotrol接收的参数aaa是username的初始值
username:FormCotrol = new FormCotrol("aaa");

(2)FormGroup:FormGroup既可以代表表单的一部分也可以用于代表整个表单,它是多个FormCotrol的集合,FormGroup将多个FormCotrol的值和状态聚合在一起。如果一个FormCotrol是无效的,那么整个FormGroup都是无效的。
优点:在管理表单中多个相关联的字段时,使用FormGroup是很方便的,比如一个日期范围,有起始和终止日期两个input,这两个input可以放到一个FormGroup中,当其中一个任何一个字段的值无效时都会显示一个错误信息。

如何创建一个FormGroup,示例:

//FormGroup的构造函数需要一个对象
formModel:FormGroup = new FormGroup({
    fromDate: new FormCotrol(),
    toDate: new FormCotrol()
});

(3)FormArray:FormArray和FormGroup是类似的,但是它有一个额外的长度属性,一般来说FormGroup用来代表整个表单或者表单字段的一个固定的子集。而FormArray通常用来代表一个可以增长的字段集合。

如何创建一个FormArray,示例:

//FormArray的构造函数是一个数组
emails:FormArray = new FormArray([
    new FormCotrol("a@qq.com"),
    new FormCotrol("b@qq.com")
]);

2、响应式表单指令

48.png

使用时,上图第二列要用属性绑定语法,即[formGroup]的形式,而第三列不需要用属性绑定语法。

示例
1.修改app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


import { AppComponent } from './app.component';
import { ReactiveFormComponent } from './reactive-form/reactive-form.component';

// 引入响应式表单
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    ReactiveFormComponent
  ],
  imports: [
    BrowserModule,
    //引入
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2.修改reactive-form.component.ts

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

//引入文件
import { FormGroup,FormControl,FormArray } from '@angular/forms';
@Component({
  selector: 'app-reactive-form',
  templateUrl: './reactive-form.component.html',
  styleUrls: ['./reactive-form.component.css']
})
export class ReactiveFormComponent implements OnInit {

  // 1.定义一个名为"myFormModel"的formGroup,用它来表示整个表单
  myFormModel:FormGroup = new FormGroup({
    // 3.声明一个formGroup,里面包含两个FormControl
    dateRange: new FormGroup({
      formDate:new FormControl(),
      toDate:new FormControl()
    }),
    emails:new FormArray([
      new FormControl("a@qq.com"),
      new FormControl("b@qq.com"),
      new FormControl("c@qq.com")
    ]),
    username2:new FormControl("name2")

  });

    // 5.定义一个名为username的FormControl
    username:FormControl = new FormControl("namenamename");

  constructor() { }

  ngOnInit() {
  }
  // 2.处理保存方法,打印myFormModel的值
  mySubmit(){
    console.log(this.myFormModel.value);
  }

  // 4.增加邮箱方法
  addEmail(){
    let emails = this.myFormModel.get("emails") as FormArray;
    emails.push(new FormControl());
  }
}

3.修改reactive-form.component.html

<!-- 
  1.通常情况下,会用一个绑定到form标签的formGroup对象来代表整个表单
  用formGroup属性绑定到后台定义的myFormModel
  这样就把整个表单的处理方式变成了响应式表单的处理方式
 -->
 <!-- 2.提交方法 -->
<form [formGroup] = "myFormModel" (submit)="mySubmit()">
  <!-- 3.用formGroupName来连接一个formGroup -->
  <div formGroupName="dateRange">
    <!-- 
      4.formControlName必须声明在formGroup内,来连接formGroup中的formControl和页面上的dom元素
     -->
    起始日期:<input type="date" formControlName="formDate"><br><br>
    截至日期:<input type="date"  formControlName="toDate">
  </div>
  <!-- 5.formArrayName也必须放在formGroup范围内 -->
  <div>
    <ul formArrayName="emails">
      <!-- 6.因为FormArray是用下标来显示每条数据的,所以一般配合ngFor来一起使用 -->
      <li *ngFor="let e of this.myFormModel.get('emails').controls;let i = index;" style="list-style: none">
        <!-- 这里要用属性绑定[formControlName] -->
        邮箱:<input type="text" [formControlName] = "i"><br>
      </li>
    </ul>
    <!-- 7.绑定click事件 -->
    <button type="button" (click)="addEmail()">增加email</button>
  </div>
  <div>
    <br>
    <button type="submit">保存</button>
  </div>
  <!-- 9.这种方式才会在formGroup的数据模型里 -->
  <input type="text" formControlName = "username2">
</form>
<br>
<!-- 
  8.formControl指令不能放在formGroup的内部
    这个username不在formGroup里,所以点击保存不会打印出来
 -->
<input type="text" [formControl] = "username">

4.结果

49.png

3、响应式表单重构用户注册表

1.修改app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


import { AppComponent } from './app.component';
import { ReactiveRigistComponent } from './reactive-rigist/reactive-rigist.component';

//引入响应式表单
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    ReactiveRigistComponent
  ],
  imports: [
    BrowserModule,
    //引入响应式表单
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2.修改reactive-rigist.component.html

<form [formGroup] = "myFormGroup">
  <p>用户名:<input type="text" formControlName = "username"></p>
  <p>手机号:<input type="text" formControlName = "mobile"></p>
  <div formGroupName = "passwordGroup">
    <p>密码:<input type="password" formControlName = "pwd"></p>
    <p>确认密码:<input type="password" formControlName = "pconfirm"></p>
  </div>
  <button type="submit" (click) = "mySubmit()">提交</button>
</form>

3.修改reactive-rigist.component.ts

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

//引入
import { FormGroup,FormControl } from '@angular/forms';

@Component({
  selector: 'app-reactive-rigist',
  templateUrl: './reactive-rigist.component.html',
  styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {

  myFormGroup:FormGroup;
  constructor() { 
    this.myFormGroup = new FormGroup({
      username:new FormControl(),
      mobile:new FormControl(),
      passwordGroup:new FormGroup({
        pwd:new FormControl(),
        pconfirm:new FormControl()
      })
    })
   }
  mySubmit(){
    console.log(this.myFormGroup.value);
  }
  ngOnInit() {
  }

}

4.结果

50.png

formBuilder

将上个例子中的

constructor() { 
    this.myFormGroup = new FormGroup({
      username:new FormControl(),
      mobile:new FormControl(),
      passwordGroup:new FormGroup({
        pwd:new FormControl(),
        pconfirm:new FormControl()
      })
    })
 }

用 formBuilder 替换后

constructor(fb:FormBuilder) { 
    this.myFormGroup = fb.group({
      username:[''],
      mobile:[''],
      passwordGroup:fb.group({
        pwd:[''],
        pconfirm:['']
      })
    })
   }

最终的效果是一样的。

<4>表单校验

1、angular的校验器

校验器就是一个普通的方法,该方法接收一个参数,参数类型必须为AbstractControl,必须要有一个返回值,返回值可以是任意结构的一个对象,这个对象的key必须是string类型的。
例如:

xxxx(control:AbstractControl):{[key:string]:any} {
   return null;
}

angular自带校验器例子:

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

//引入
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';

@Component({
  selector: 'app-reactive-rigist',
  templateUrl: './reactive-rigist.component.html',
  styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
  myFormGroup:FormGroup;

  constructor(fb:FormBuilder) { 
    this.myFormGroup = fb.group({
      // 第一个是默认值,第二个是校验器
      // 单个校验器的写法
      // username:['',[Validators.required,Validators.minLength(6)]],
      // 多个校验器的写法
      username:['',[Validators.required,Validators.minLength(6)]],
      mobile:[''],
      passwordGroup:fb.group({
        pwd:[''],
        pconfirm:['']
      })
    })
   }
  mySubmit(){
    let isValid:boolean = this.myFormGroup.get("username").valid;

    console.log("username的校验结果"+isValid);
    let errors:any = this.myFormGroup.get("username").errors;

    console.log("username的错误信息是"+JSON.stringify(errors));
    console.log(this.myFormGroup.value);
  }
  ngOnInit() {
  }

}

结果

51.png

2、自定义校验器

1.

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

//引入
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';

@Component({
  selector: 'app-reactive-rigist',
  templateUrl: './reactive-rigist.component.html',
  styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {

//自定义手机号校验器
  mobileValidator(control:FormControl):any {
    // 手机号正则表达式
    var myreg=/^(((13[0-9]{1})|15[0-9]{1})|(18[0-9]{1}))+\d{8}$/;
    let valid = myreg.test(control.value);
    console.log("mobile的校验结果是:"+valid);
    return valid ? null : {mobile : true};
  }
  myFormGroup:FormGroup;

  constructor(fb:FormBuilder) { 
    this.myFormGroup = fb.group({
      username:['',[Validators.required,Validators.minLength(6)]],
      //添加自定义的校验器
      mobile:['',this.mobileValidator],
      passwordGroup:fb.group({
        pwd:[''],
        pconfirm:['']
      })
    })
   }
  mySubmit(){
    let isValid:boolean = this.myFormGroup.get("username").valid;

    console.log("username的校验结果"+isValid);
    let errors:any = this.myFormGroup.get("username").errors;

    console.log("username的错误信息是"+JSON.stringify(errors));
    console.log(this.myFormGroup.value);
  }
  ngOnInit() {
  }

}

2、结果

52.png

3、为FormGroup自定义校验器

1、

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

//引入
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';

@Component({
  selector: 'app-reactive-rigist',
  templateUrl: './reactive-rigist.component.html',
  styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
  mobileValidator(control:FormControl):any {
    var myreg=/^(((13[0-9]{1})|15[0-9]{1})|(18[0-9]{1}))+\d{8}$/;
    let valid = myreg.test(control.value);
    console.log("mobile的校验结果是:"+valid);
    return valid ? null : {mobile : true};
  }

//自定义方法
  equalValidator(group:FormGroup):any {
    let pwd:FormControl = group.get("pwd") as FormControl;
    let pconfirm:FormControl = group.get("pconfirm") as FormControl;
    let valid:boolean = (pwd.value === pconfirm.value);
    console.log("密码校验结果:"+valid);
    // 当校验通过时返回null,当校验不通过的时候返回{equal : true}
    return valid ? null : {equal : true};
  }


  myFormGroup:FormGroup;

  constructor(fb:FormBuilder) { 
    this.myFormGroup = fb.group({
      username:['',[Validators.required,Validators.minLength(6)]],
      mobile:['',this.mobileValidator],
      passwordGroup:fb.group({
        pwd:[''],
        pconfirm:['']
      // 加入声明,是一个对象
      },{validator:this.equalValidator})
    })
   }
  mySubmit(){
    let isValid:boolean = this.myFormGroup.get("username").valid;

    console.log("username的校验结果"+isValid);
    let errors:any = this.myFormGroup.get("username").errors;

    console.log("username的错误信息是"+JSON.stringify(errors));
    console.log(this.myFormGroup.value);
  }
  ngOnInit() {
  }

}

4、将校验器单独放到一个文件中,然后用export的方式暴露出去

·1.在app目录下新建一个文件夹

53.png

2.将刚刚定义的方法放置到validators.ts中


//引入文件
import { FormGroup,FormControl } from '@angular/forms';

// 注意:此时这两个不再是一个TypeScript方法了,而是全局的一个函数
// 要用function来声明

export function mobileValidator(control:FormControl):any {
    // 手机号正则表达式
    var myreg=/^(((13[0-9]{1})|15[0-9]{1})|(18[0-9]{1}))+\d{8}$/;
    let valid = myreg.test(control.value);
    console.log("mobile的校验结果是:"+valid);
    return valid ? null : {mobile : true};
  }

  export function equalValidator(group:FormGroup):any {
    let pwd:FormControl = group.get("pwd") as FormControl;
    let pconfirm:FormControl = group.get("pconfirm") as FormControl;
    let valid:boolean = (pwd.value === pconfirm.value);
    console.log("密码校验结果:"+valid);
    // 当校验通过时返回null,当校验不通过的时候返回{equal : true}
    return valid ? null : {equal : true};
  }

3.在组件中引入这两个全局的方法

import { Component, OnInit} from '@angular/core';
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';

//引入文件
import {mobileValidator,equalValidator} from '../validator/validators';
@Component({
  selector: 'app-reactive-rigist',
  templateUrl: './reactive-rigist.component.html',
  styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {

  myFormGroup:FormGroup;
  
  constructor(fb:FormBuilder) { 
    this.myFormGroup = fb.group({
      username:['',[Validators.required,Validators.minLength(6)]],

      //此次修改
      mobile:['',mobileValidator],
      passwordGroup:fb.group({  
        pwd:[''],
        pconfirm:['']

        // 此处修改
      },{validator:equalValidator})
    })
   }
  mySubmit(){
    let isValid:boolean = this.myFormGroup.get("username").valid;
    console.log("username的校验结果"+isValid);
    let errors:any = this.myFormGroup.get("username").errors;
    console.log("username的错误信息是"+JSON.stringify(errors));
    console.log(this.myFormGroup.value);
  }
  ngOnInit() {
  }

}

4.结果是相同的

5、用.myFormGroup的valid属性来判断整个表单中所有的值是否是合法的

1.修改代码

mySubmit(){

    if(this.myFormGroup.valid) {
      //只有合法时才打印模型信息
      console.log(this.myFormGroup.value);
    }else {
      console.log("校验未通过");
    }

  }

2.结果

54.png

6、校验不通过时,显示错误信息给用户

1.修改模版

<form [formGroup]="myFormGroup">
    <p>用户名:<input type="text" formControlName="username"></p>
    <!-- 新增校验信息 -->
    <!-- 当校验不通过时返回true,所以取反 -->
    <div [hidden]="!myFormGroup.hasError('required','username')">
        用户名是必填项
    </div>
    <div [hidden]="!myFormGroup.hasError('minlength','username')">
      用户名最小长度是6位
    </div>
    <p>手机号:<input type="text" formControlName="mobile"></p>
    <div [hidden]="!myFormGroup.hasError('mymobile','mobile')">
      请输入正确的手机号
    </div>
    <div formGroupName="passwordGroup">
        <p>密码:<input type="password" formControlName="pwd"></p>
        <p>确认密码:<input type="password" formControlName="pconfirm"></p>
    </div>
    <div [hidden]="!myFormGroup.hasError('myequal','passwordGroup')">
      密码输入不一致
    </div>
    <button type="submit" (click)="mySubmit()">提交</button>
</form>

2.结果

55.png

56.png
57.png

7、在检验器中写错误信息

1.修改validators.ts

export function equalValidator(group:FormGroup):any {
    let pwd:FormControl = group.get("pwd") as FormControl;
    let pconfirm:FormControl = group.get("pconfirm") as FormControl;
    let valid:boolean = (pwd.value === pconfirm.value);
    console.log("密码校验结果:"+valid);
    // return valid ? null : {myequal : true};
    // 在此处添加错误信息
    return valid ? null : {myequal : {errorInfo:"密码输入不一致"}};

  }

2.修改模板

<div formGroupName="passwordGroup">
        <p>密码:<input type="password" formControlName="pwd"></p>
        <!-- 在嵌套在formGroup内的校验,要写成数组['passwordGroup','pwd'] -->
        <div [hidden]="!myFormGroup.hasError('minlength',['passwordGroup','pwd'])">
            密码最少6位
        </div>
        <p>确认密码:<input type="password" formControlName="pconfirm"></p>
    </div>
    <div [hidden]="!myFormGroup.hasError('myequal','passwordGroup')">
        <!-- 此处修改为 -->
        {{myFormGroup.getError('myequal','passwordGroup')?.errorInfo}}
    </div>

3.结果相同

8、异步校验器

将mobile检验器改为异步校验器
1.修改validators.ts

import{ Observable } from "rxjs";
// 异步校验器
  export function mobileAsyncValidator(control:FormControl):any {
    // 手机号正则表达式
    var myreg=/^(((13[0-9]{1})|15[0-9]{1})|(18[0-9]{1}))+\d{8}$/;
    let valid = myreg.test(control.value);
    console.log("mobile的校验结果是:"+valid);
    // 将返回值放到一个流里面返回
    return Observable.of( valid ? null : {mymobile : true}).delay(5000);
  }

2.修改reactive-rigist.component.ts

      mobile:['',mobileValidator,mobileAsyncValidator]

3.修改模版
添加

<div>
    {{myFormGroup.status}}
</div>

4.结果

58.png

59.png

5秒后


60.png

<5>状态字段

包括:touched和untouched 、 pristine和dirty 、 pending
touched和untouched:
用来判断用户是否访问过这个字段,也就是这个字段是否获取过焦点。若获取过焦点,则touched是true,untouched 是false。

<p>用户名:<input type="text" formControlName="username"></p>
    <!-- 当username通过校验,或者状态是untouched时隐藏校验信息 -->
    <div [hidden]="myFormGroup.get('username').valid ||myFormGroup.get('username').untouched">
        <div [hidden]="!myFormGroup.hasError('required','username')">
            用户名是必填项
        </div>
        <div [hidden]="!myFormGroup.hasError('minlength','username')">
            用户名最小长度是6位
        </div>
    </div>

pristine和dirty
如果一个字段的值从来没被改变过,那么pristine为true,dirty为false。

<!-- moblie通过校验或者值从来没被修改过,隐藏错误信息 -->
    <div[hidden]="myFormGroup.get('mobile').valid ||myFormGroup.get('mobile').pristine">
        <div [hidden]="!myFormGroup.hasError('mymobile','mobile')">
            请输入正确的手机号
        </div>
    </div>

pending
当一个字段正处于异步检验时,pending为true

<div [hidden]="!myFormGroup.get('mobile').pending">
        正在校验手机号合法性
</div>

注意
针对所有的字段,angular会自动根据字段的状态来为它添加一些样式。

61.png

.myError {
    border: 1px solid red;
}
    <!-- 当这个字段无效且状态为touched时,增加myError类 -->
<p>用户名:<input [class.myError]="myFormGroup.get('username').invalid && myFormGroup.get('username').touched" type="text" formControlName="username"></p>
62.png

<6>模版式表单校验

1、生成两个指令
指令可以被看成是一个没有模版的component,指令是作为属性来用的。

ng g directive directives/moblieValidator

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

推荐阅读更多精彩内容