• 利用angular4和nodejs-express构建一个简单的网站(七)—用户注册之ReactiveForm


    这一节对用户注册组件进行分析。
    用户注册组件主要涉及angular4表单的操作。Angular提供了两种构建表单的技术:响应式表单和模板驱动表单。 这两项技术都属于@angular/forms库,并且共享一组公共的表单控件类。我在用户注册组件(regist.component)中使用的是响应式表单(ReactiveFormsModule),要了解更多angular表单的知识,可以访问官方文档,里面介绍的很详细。

    注册组件模板分析

    用户注册需要用户名、密码、邮箱(非必须)三个信息注册表单组件的模板代码如下:

    <form [formGroup]="registForm" (ngSubmit)="onSubmit()" novalidate>
        <div class="form-group">
          <label for="name">User name</label>
          <input class="form-control" formControlName="name" id="name" required>
          <div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
            <div *ngIf="name.errors.required">
              Name is required!
            </div>
            <div *ngIf="name.errors.minlength">
              Name must be at least 4 characters long.
            </div>
            <div *ngIf="name.errors.pattern">
              Name must be composed of letters, numbers
            </div>
          </div>
        </div>
        <div class="form-group">
          <label for="password">Password</label>
          <input class="form-control" formControlName="password" type="password" required id="password" #pass>
          <div *ngIf="password.invalid && (password.dirty || password.touched)" class="alert alert-danger">
            <div *ngIf="password.errors.required">
              Password is required!
            </div>
            <div *ngIf="password.errors.minlength">
              Password must be at least 8 characters long.
            </div>
            <div *ngIf="password.errors.pattern">
              <!--密码必须由字母、数字、下划线和减号组成,首字母要求大写 -->
              Password must be composed of letters, numbers, '_', '-' and Capital letters must be capitalized.
            </div>
          </div>
        </div>
        <div class="from-group">
          <label for="repassword">Re Password</label>
          <input type="password" class="form-control" required id="repassword" (focus)="checkValid()"
           formControlName="repassword">
          <div class="alert alert-danger" *ngIf="repassword.invalid && (repassword.dirty || repassword.touched)">
            <div *ngIf="repassword.errors.required">
              Re password is required!
            </div>
            <div *ngIf="repassword.errors.comparePassword">
              Re password must equal password!
            </div>
          </div>
        </div>
        <div class="form-group email-group">
          <label for="email">Email</label>
          <input class="form-control" formControlName="email" type="email" id="email">
          <div *ngIf="email.invalid &&(email.dirty || email.touched)" class="alert alert-danger">
            <div *ngIf="email.errors.pattern">
              The email address format is incorrect
            </div>
          </div>
        </div>
        <div class="form-group form-btn">
          <button type="submit" class="btn btn-primary" [disabled]="registForm.invalid">Submit</button>
          <button type="button" class="btn btn-light" [disabled]="registForm.pristine" (click)="revert()">Cancel</button>
        </div>
      </form>

    导航到regist组件后在name、password、repassword、email中添加相应的信息,点击Submit按钮,就会触发ngSubmit事件,在form标签中定义处理ngSubmit事件的函数onSubmit(),onSubmit()函数将注册信息发送到服务器。
    novalidate阻止浏览器使用原生HTML表单验证,因为这里使用了angular的表单验证。
    对于响应式表单需要在模板的form标签中声明formGroup(在这里formGroup声明为registForm),还需要在输入控件(如input、select等)标签中声明formControlName。
    模板中还有一些关于表单验证的内容,如下面的代码:

    <div *ngIf="password.invalid && (password.dirty || password.touched)" class="alert alert-danger">
            ...
    </div>

    在表单状态为dirty(脏)状态和touched(碰过)状态时如果password为invalid(不合法,表单控件不合法(invalid)表示未能满足控件的验证规则),div标识符中的内容将呈现到password控件的下方。违反了不同的验证规则,会呈现不同的内容,如在上一段代码中的div标签中还包裹着:

        <div *ngIf="password.errors.required">
              Password is required!
        </div>

    表明在违反了“password.errors.required”规则时,会呈现“Password is required!”内容。
    在提交按钮(Submit)上的标记[disabled]="registForm.invalid",表示当form表单有不符合验证规则的输入时,按钮不能使用。
    取消输入按钮(Cancel)在控件值未发生变化时(registForm.pristine)不能使用。
    模板的基本分析就到这里,下面我们来看看ts文件中的组件类。

    注册组件组件类分析

    注册组件的组件类设计内容较多,在这里分部进行分析。
    首先要创建响应式表单并定义表单的认证规则。需要从forms模块中引入FormBuilder、 FormGroup和Validators类。

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

    并在构造方法中声明并初始化这三个类。

    constructor(
        ...
        private fb: FormBuilder,
        private userSer: UserService,
        private tokenServ: AuthTokenService) {
        ...
      }

    下一步利用FormBuilder创建表单。创建一个方法createForm(),用于创建表单,方法中的代码如下:

    this.registForm = this.fb.group({
          'name': [this.user.name, [
            Validators.required,
            Validators.minLength(4),
            Validators.pattern(/^[a-z]|[A-Z]|[0-9]$/)]],
          'password': [this.user.password,
          [Validators.required,
          Validators.minLength(8),
          Validators.pattern(/^[A-Z][a-zA-Z0-9_-]+$/)]],
          'email': [this.user.email,
          Validators.pattern(/^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+).([a-zA-Z]{2,4})$/)],
          'repassword': [this.user.password, [
            Validators.required]]
        });

    registForm是一个FormGroup的实例,关联模板中的formGroup([formGroup]="registForm"),在类中进行声明:

    registForm: FormGroup;

    利用FormBuilder.group来生成响应式表单,FormBuilder.group是一个用来创建FormGroup的工厂方法,它接受一个对象,对象的键和值分别是FormControl的名字和它的定义。在这个对象中对name、password、email、repassword四个FormControl进行了初始化。定义了这四个FormControl的初始值对应User类的对象user的四个同名属性(repassword对应的是user.password,用于对用户密码的重复输入进行验证)。user对象也是在类中定义的:

    user: User = new User(0, '', '', '');

    表单验证

    在FormControl的初始化中还定义了验证规则,这个表单的验证规则由以下几种:

    • 必须输入内容(Validators.required)
    • 最少需要x个字符(Validators.minlength(x))
    • 正则验证,必须由字母、数字组成 Validators.pattern(/^[a-z]|[A-Z]|[0-9]$/)
    • 正则验证,必须由字母、数字、下划线和减号组成,首字母要求大写 Validators.pattern(/^[A-Z][a-zA-Z0-9_-]+$/)]]
    • 必须符合email格式要求,可以使用Validators.email,也可以使用正则验证。

    对FormControl进行验证,还需要编写get方法来访问表单控件:

      get name() { return this.registForm.get('name'); }
      get password() { return this.registForm.get('password'); }
      get email() { return this.registForm.get('email'); }
      get repassword() { return this.registForm.get('repassword'); }

    这里还需要自定义一个验证器,用于验证repassword输入的值是否和password的值相同。
    自定义验证器由一个验证工厂函数构成。代码如下:

    import { AbstractControl,ValidatorFn } from '@angular/forms';
    
    export function passwordEquals(password: string): ValidatorFn {
        return (control: AbstractControl): { [key: string]: any } => {
            const isEquals = (password === control.value);
            return isEquals ? null : { 'comparePassword': control.value };
        }
    }

    passwordEquals()方法需要传入一个string类型的参数,返回配置好的验证器函数。该函数接受一个Angular控制器对象,在控制器的值和参数相同时返回null,不相同时返回验证错误对象,错误对象是一个现实控件值的键值对。
    将自定义验证器加到表单的repassword属性上,但因为passwordEquals()的参数需要的是password控件的值,而password控件的值不能在表单创建时拿到,需要在password控件有值后才能拿到。那么,进行自定义验证器加载的最好时机就是repassword控件获得焦点的时候。所以,在模板中要加入repassword控件的标签中加入焦点事件:(focus)="checkValid()",在处理焦点事件的checkValid()函数中,为repassword加入自定义验证规则,判断它的值是否和控件password的值相同:

    checkValid() {
        this.repassword.setValidators([Validators.required, passwordEquals(this.pass.nativeElement.value)]);
      }

    this.pass是通过在password的<input>组件中声明一个引用变量#pass后,通过@ViewChild('pass') pass: ElementRef;获取到password的<input>组件的值。
    关于用户注册中响应式表单(ReactiveForm)的构建和验证基本上就是这些了,下一章将要介绍如何向服务器发送注册信息并导航到下一个模块。

    关于angular表单验证规则和验证方法可以查看官方文档中的介绍。

  • 相关阅读:
    nullptr和NULL
    tmux用于恢复远程屏幕
    如何改变git的默认路径
    scp拷贝文件
    C++头文件<bits/stdc++.h>
    MAME模拟器使用简单教程
    typescript接口扩展
    Typescript中的可索引接口 类类型接口
    typescript函数类型接口
    typescript静态属性 静态方法 抽象类 多态
  • 原文地址:https://www.cnblogs.com/10manongit/p/12821611.html
Copyright © 2020-2023  润新知