angular【响应式表单】和【模板式表单】校验器对比分析---angular总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a954553391/article/details/88838350

前言:angular为我们提供了两种表单形式,一种是响应式表单,另一种是模板式表单。那么这两种表单有什么区别呢?它们各自的应用场景又是什么样的呢?什么是angular的校验器?校验器能够帮助我们实现什么功能?它又是怎样在响应式表单和模板式表单中应用的呢?下面的文章中,将会和大家分享一下关于angular响应式表单校验器和模板式表单校验器的内容。

(一)是什么

1.校验器

在我们注册一个邮箱的时候,我们需要输入用户名、密码、手机号、邮箱等内容。此时会出现,用户名没有输入,或者手机号位数不正确等内容。那么如何判这些内容呢,这时候就用到了校验器。通过校验器,可以帮助用户在登录的时候完成判断。
在Angular中为我们提供了几个内置 validators (校验器),但在实际工作中为了满足项目需求,我们经常需要为应用添加一些自定义验证功能。同时校验器也有同步和异步的区别。

2.【响应式表单】和【模板式表单】校验器应用场景分析

响应式表单 模板式表单
复杂场景 (需求多、需要处理内容细 简单场景(需求少、处理内容简单)

(二)应用

下面以用户注册页面为例,要完成如下的内容:

用户名:必填,为六位 需要向服务端发出请求,判断是否已存在,需要自定义异步验证
电话号码:必须以13-、15-、18-开头,长度为11位
密码:必填 使用angular内置验证器
确认密码:必填,必须和密码相同 使用自定义同步验证器。

输入内容之前,校验器会提示:
在这里插入图片描述
按要求输入之后:

在这里插入图片描述
结果如下:
在这里插入图片描述
因为是异步操作,并且设置时间为5秒,所以在输入正确手机号之后,INVALID会变成 VALID。

【状态字段】
刚打开页面的时候,用户还没有进行任何操作,此时提示“用户名是必填项”,显然是不合理的,这时候就用到了,状态字段。通过状态字段可以设置,用户刚进入界面,没有任何操作时,隐藏提示“用户名是必填项”。

(1) touched untouched:控制错误信息是否现实;字段是否获取过焦点,如果任一个字段是touched,所有的都是toched,只有所有是untouched,才是untouched.
(2) pristine dirty:字段的值是否变过 任意一个字段是Dirty,所有字段都是Dirty,pristine反之
(3)pending:为true时,正在校验

(三)代码

以用户注册为例:

因为功能相同,所以此处先写公共的表单校验器代码:

import { FormControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
export function mobileValidator(control: FormControl): any {
    const myreg = /^(((13[0-9]{1}) | (15[0-9]{1}) | (18[0-9]{1})) +\d{8})$/;
    const valid = myreg.test(control.value);
    console.log('mobile的校验结果是:' + valid);
    return valid ? null : {mobile : true};
   }

export function mobileAsyncValidator(control: FormControl): any {
     const myreg = /^(((13[0-9]{1}) | (15[0-9]{1}) | (18[0-9]{1})) +\d{8})$/;
     const valid = myreg.test(control.value);
     console.log('mobile的校验结果是:' + valid);
     return Observable.of(valid ? null : { mobile : true}).delay(5000);
   }
export function equalValidator(group: FormGroup): any {
     const password: FormControl = group.get('password') as FormControl;
     const pconfirm: FormControl = group.get('pconfirm') as FormControl;
     const valid: boolean = (password.value === pconfirm.value);
     console.log('密码校验结果:' + valid);
     return valid ? null : { equal : {descxxx: '密码和确认密码不匹配'}};
   }

1.响应式表单

(1)html内容

<form [formGroup]="formModel" (submit)="onSubmit()">
    <div>用户名:<input [class.hasError]="formModel.get('username').invalid && formModel.get('username').touched "type="text" formControlName="username"></div>
    <div [hidden]="formModel.get('username').valid || formModel.get('username').untouched ">
        <div [hidden]="!formModel.hasError('required','username')">
         用户名是必填项
        </div>
        <div [hidden]="!formModel.hasError('minlength','username')">
         用户名最小长度是6
        </div> 
    </div>
    <div>手机号:<input type="text"  formControlName="mobile"></div>
    <div [hidden]="formModel.get('mobile').valid || formModel.get('mobile').pristine ">
      <div [hidden] ="!formModel.hasError('mobile','mobile')">
         请输入正确的手机号
      </div>
    </div>
    <div [hidden]="!formModel.get('mobile').pending">
        正在验证手机号合法性
    </div> 
    <div formGroupName="passwordsGroup">
      <div>密码:<input type="password" formControlName="password"></div>
      <div [hidden]="!formModel.hasError('minlength',['passwordsGroup','password'])">
          密码最小长度是6
      </div>
      <div>确认密码:<input type="password"  formControlName="pconfirm"></div>
      <div [hidden]="!formModel.hasError('equal','passwordsGroup')">
          {{formModel.getError('equal','passwordsGroup')?.descxxx}}
      </div>
    </div>
    <button type="submit">注册</button>
  </form>
  <div>
    {{formModel.status}}
  </div>

(2)ts内容

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators, ValidatorFn } from '@angular/forms';
import { mobileAsyncValidator, mobileValidator } from '../Validator/validators';

@Component({
  selector: 'app-reactive-regist',
  templateUrl: './reactive-regist.component.html',
  styleUrls: ['./reactive-regist.component.css']
})
export class ReactiveRegistComponent implements OnInit {
  formModel: FormGroup;
  mobileValidator: any;
  equalValidator: any | ValidatorFn | ValidatorFn[];

  constructor(fb: FormBuilder) {
    this.formModel = fb.group ({
      username: ['', [Validators.required, Validators.minLength(6)]],
      mobile: ['', mobileValidator, mobileAsyncValidator],
      passwordsGroup: fb.group ({
        password: ['', Validators.minLength(6)],
        pconfirm: ['']
      }, {validator: this.equalValidator})
    });
  }
  onSubmit() {
    const isValid: boolean = this.formModel.get('username').valid;
    console.log('username的校验结果:' + isValid);
    const errors: any = this.formModel.get('username').errors;
    console.log('username的错误信息:' + JSON.stringify(errors));
    if (this.formModel.valid) {
      console.log(this.formModel.value);
    }

  }

  ngOnInit() {
  }

}

2.模板式表单

(1)html内容

<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value,myForm.valid)" novalidate>
  <div>用户名:<input  ngModel required minlength="6" name="username"  type="text" (input)="onMobileInput(myForm)"></div>
  <div [hidden]="mobileValid || mobileUntouched">
      <div [hidden]="!myForm.form.hasError('required','username')">
      用户名是必填项
      </div>
  </div>
  <div [hidden]="!myForm.form.hasError('minlength','username')">
    用户名最小长度是6
   </div>  
  <div>手机号:<input ngModel name="mobile" type="text"></div>
  <div [hidden] ="!myForm.form.hasError('mobile','mobile')">
    请输入正确的手机号
 </div>
  <div ngModelGroup="passwordsGroup">
    <div>密码:<input ngModel minlength="6" name="password" type="password"></div>
    <div [hidden]="!myForm.form.hasError('minlength',['passwordsGroup','password'])">
      密码最小长度是6
    </div>
    <div>确认密码:<input ngModel name="pconfirm" type="password"></div>
    <div [hidden]="!myForm.form.hasError('equal','passwordsGroup')">
      {{myForm.form.getError('equal','passwordsGroup')?.descxxx}}
    </div>
  </div>
  <button type="submit">注册</button>
</form>

(2)ts内容
模板式表单不能使用状态的字段属性,因此需要写入如下代码:

import { Component, OnInit } from '@angular/core';
import { pipeFromArray } from 'rxjs/internal/util/pipe';
import { NgForm } from '@angular/forms';
import { from } from 'rxjs/internal/observable/from';

@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, valid: boolean) {
     console.log(valid);
     console.log(value);
   }

   // tslint:disable-next-line:member-ordering
   mobileValid = true;
   // tslint:disable-next-line:member-ordering
   mobileUntouched = true;

   onMobileInput(form: NgForm ) {
     if ( form ) {
       /* this.mobileValid = from.form.get('mobile').valid */
       this.mobileUntouched = form.form.get('mobile').untouched;
     }
   }
}

(3)directive.ts内容
①equal指令

import { Directive } from '@angular/core';
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
import { mobileValidator, equalValidator } from '../Validator/validators';

@Directive({
  // tslint:disable-next-line:directive-selector
  selector: '[ equal ]',
  providers: [ { provide: NG_ASYNC_VALIDATORS, useValue: equalValidator , multi: true}]
})
export class EqulaValidatorDirective {

  constructor() { }

}

②mobie指令

import { Directive } from '@angular/core';
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
import { mobileValidator } from '../Validator/validators';

@Directive({
  // tslint:disable-next-line:directive-selector
  selector: ' [ mobile ] ' ,
  providers: [ { provide: NG_ASYNC_VALIDATORS, useValue: mobileValidator , multi: true}]
})
export class MobileValidatorDirective {

  constructor() { }

}

总结:在Angular的表单应用中,选择哪种表单需要根据不同的场景来选择。由于响应式表单可以在代码里创建结构,同步立即可用,而模板式表单需要额外声明变量。因此响应式表单的应用比模板式表单的应用范围更广泛。

总结:初次接触验证器的时候,会觉得非常迷惑,但是通过使用验证器可以让我们的业务逻辑更简洁,将复杂的验证工作统统放到验证器中,特别是在大型表单场景下,会非常方便。如果有相同的验证规则也可以通过写入一个公共的验证器,还可以提高代码的重用性,让我们变成更加高效。

猜你喜欢

转载自blog.csdn.net/a954553391/article/details/88838350