Angular表单

Angular中表单分为两种,一种是是模板驱动表,一种是响应式表单。以下分别对模板驱动表单,响应式表单的使用,表单的验证做示例。

1. 模板驱动型表单

1.1模板表单的使用

要使用模板驱动行表单首先需要在根模块下面引入FormsModule,然后将FormsModule模块导入到根模块的ngModule中的imports数组中,这样才能够就能访问模板驱动表单的所有特性,包括 ngModel

模块的引用

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { ReactiveFormComponent } from './reactive-form/reactive-form.component';
import { HeroFormComponent } from './hero-form/hero-form.component';
import { RighsterFormComponent } from './righster-form/righster-form.component';
const routes: Routes = [
  {
    path: 'heroForm',
    component: HeroFormComponent
  },
  {
    path: 'loginForm',
    component: LoginComponent
  },
  {
    path: 'reactiveForm',
    component: ReactiveFormComponent
  },
  {
    path: 'registerForm',
    component: RighsterFormComponent
  },
  {
    path: '',
    redirectTo: 'heroForm',
    pathMatch: 'full'
  }
];

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    ReactiveFormComponent,
    HeroFormComponent,
    RighsterFormComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    RouterModule.forRoot(routes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
1.2模板表单的详细介绍

新建一个login组件用来写一个注册的模板表单

其中模板为

<form action="/regist" method="post" #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)">
<div class="row"><label class="form-label">用户名:</label><input type="text" name="user" ngModel></div>
<div class="row"><label class="form-label">手机号:</label><input type="text" name="phone" ngModel></div>
<div class="row"><label class="form-label">邮编:</label><input type="number" name="youbian" ngModel></div>
<div ngModelGroup="passGroup">
  <div class="row"><label class="form-label">密码:</label><input type="password" name="password" ngModel></div>
  <div class="row"><label class="form-label">确认密码:</label><input type="password" name="repassword" ngModel></div>
</div>

<div class="row"><button type="submit">注册</button></div>
</form>
<div>{{ myForm.value | json }}</div>

ngForm:Angular 会在 <form> 标签上自动创建并附加一个 NgForm 指令。

NgForm 指令为 form 增补了一些额外特性。 它会控制那些带有 ngModel 指令和 name 属性的元素,监听他们的属性(包括其有效性)。 它还有自己的 valid 属性,这个属性只有在它包含的每个控件都有效时才是真。

myForm是一个模板变量

ngModel用于双向绑定,如上面的代码表单元素需要设置name属性,也可以写成另一种形式

<div class="row"><label class="form-label">用户名:</label><input type="text" name="user" [(ngModel)]="user"></div>

ngModelGroup可以用来分组

ngSubmit表单提交事件

myForm.value可以获取表单数据。

在表单中使用 ngModel 可以获得比仅使用双向数据绑定更多的控制权。它还会告诉你很多信息:用户碰过此控件吗?它的值变化了吗?数据变得无效了吗?

NgModel 指令不仅仅跟踪状态。它还使用特定的 Angular CSS 类来更新控件,以反映当前状态。 可以利用这些 CSS 类来修改控件的外观,显示或隐藏消息。

状态为真时的 CSS 类为假时的 CSS 类
控件被访问过。ng-touchedng-untouched
控件的值变化了。ng-dirtyng-pristine
控件的值有效。ng-validng-invalid

2. 响应式表单

2.1响应式表单简介

响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 的流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,同时,也赋予你对数据进行同步访问的能力。这种方式允许你的模板利用这些表单的“状态变更流”,而不必依赖它们。

响应式表单与模板驱动的表单有着显著的不同点。响应式表单通过对数据模型的同步访问提供了更多的可预测性,使用 Observable 的操作符提供了不可变性,并且通过 Observable 流提供了变化追踪功能。

2.2 响应式表单具体使用

要使用响应式表单,首先需要在@angular/forms包中导入ReactiveFormsModule,并把它放到ngModule的imports数组中去。

FormControl:

当使用响应式表单时,FormControl 是最基本的构造块。要注册单个的表单控件,请在组件中导入 FormControl 类,并创建一个 FormControl 的新实例,把它保存在类的某个属性中。

FormGroup

正如 FormControl 的实例能让你控制单个输入框所对应的控件,FormGroup 可以跟踪一组 FormControl 实例(比如一个表单)的表单状态。当创建 FormGroup 时,其中的每个控件都会根据其名字进行跟踪。

FormBuilder

当需要与多个表单打交道时,手动创建多个表单控件实例会非常繁琐。FormBuilder 服务提供了一些便捷方法来生成表单控件。FormBuilder 在幕后也使用同样的方式来创建和返回这些实例,用起来更简单。 ,用 FormBuilder 来代替手工创建这些 FormControlFormGroup

FormArray

FormArrayFormGroup 之外的另一个选择,用于管理任意数量的匿名控件。像 FormGroup 实例一样,你也可以往 FormArray 中动态插入和移除控件,并且 FormArray 实例的值和验证状态也是根据它的子控件计算得来的。 不过,你不需要为每个控件定义一个名字作为 key,因此,如果你事先不知道子控件的数量,这就是一个很好的选择。

表单部分模型更新

当修改包含多个控件的 FormGroup 的值时,你可能只希望更新模型中的一部分,而不是完全替换掉。

修补(Patch)模型值

对单个控件,你会使用 setValue() 方法来该控件设置新值。但当应用到 FormGroup 并打算整体设置该控件的值时,setValue() 方法会受到这个 FormGroup 结构的很多约束。patchValue() 方法就宽松多了,它只会替换表单模型中修改过的那些属性,因为你只想提供部分修改。setValue() 中严格的检查可以帮你捕获复杂表单嵌套时可能出现的错误,而 patchValue() 将会默默地走向失败。

eg:

 this.profileForm.patchValue({
    firstName: 'Nancy',
    address: {
      street: '123 Drew Street'
    }
  });

先举一个不使用FormBuilder服务创建控件的方法

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 {
  formModel: FormGroup = new FormGroup({
    dateRange: new FormGroup({
      from: new FormControl(),
      to: new FormControl()
    }),
    emails: new FormArray([
      new FormControl('aaa@a.com'),
      new FormControl('bbb@b.com'),
    ]
  )
  });
  username: FormControl = new FormControl('aa');
  constructor() { }

  ngOnInit() {
  }
  addEmail(): void {
    const emails = this.formModel.get('emails') as FormArray;
    emails.push(new FormControl());
  }
  onSubmit(): void {
    console.log(this.formModel);
  }

}

模板

<form [formGroup]="formModel" (submit)="onSubmit()">
  <div formGroupName="dateRange">
    起始日期: <input type="date" formControlName="from">
    截止日期: <input type="date" formControlName="to">
  </div>
  <div>
    <ul formArrayName="emails">
      <li *ngFor="let email of this.formModel.get('emails').controls;let i=index;">
        <input type="text" [formControlName]="i">
      </li>
    </ul>
    <button type="button" (click)="addEmail()">增加email</button>
  </div>
  <button type="submit">保存</button>
</form>

再举一个使用FormBulider服务创建表单控件的例子,生成一个注册组件

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


@Component({
  selector: 'app-righster-form',
  templateUrl: './righster-form.component.html',
  styleUrls: ['./righster-form.component.css']
})
export class RighsterFormComponent implements OnInit {
  rigisterForm: FormGroup;
  isCanSubmit: boolean;
  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.createForm();
  }
  createForm() {
    this.rigisterForm = this.fb.group({
      username: ['', [Validators.required, Validators.minLength(6)]],
      mobile: ['', mobileValidator],
      passwordGroup: this.fb.group({
        password: ['', [Validators.minLength(6)]],
        pconfirm: ['']
      }, {validator: equalValidator})
    });
  }
  // 提交
  onSubmit() {
    const isValid: boolean = this.rigisterForm.get('username').valid;
    // console.log(isValid);
    // console.log( this.rigisterForm.get('username'));
    if (this.rigisterForm.valid) {
      console.log(this.rigisterForm.value);
    }
  }

}

其中关于验证的可以先忽略;

模板代码:

<h2>用户注册</h2>
<form [formGroup]="rigisterForm" (submit)="onSubmit()">
  <div class="row">
    <label>用户名:</label><input type="text" formControlName="username">
  </div>
  <div [hidden]="rigisterForm.get('username').valid || rigisterForm.get('username').untouched">
      <div [hidden]="!rigisterForm.hasError('required', 'username')">
          用户名是必填项
        </div>
        <div [hidden]="!rigisterForm.hasError('minlength', 'username')">
          用户名最小长度是6
        </div>
  </div>
  <div class="row">
    <label>手机号:</label><input type="text" formControlName="mobile">
  </div>
  <div [hidden]="rigisterForm.get('mobile').valid || rigisterForm.get('mobile').pristine">
      <div [hidden]="!rigisterForm.hasError('mobile', 'mobile')">
          请输入正确的手机号码
        </div>
  </div>

  <div formGroupName="passwordGroup">
    <div class="row">
      <label>密码:</label><input type="password" formControlName="password">
    </div>
    <div [hidden]="!rigisterForm.hasError('minLength', ['passwordGroup', 'password'])">
      密码长度最少6位
    </div>
    <div class="row">
      <label>确认密码:</label><input type="password" formControlName="pconfirm">
    </div>
    <div [hidden]="!rigisterForm.hasError('equal', 'passwordGroup')">
        两次密码输入不一致
    </div>
  </div>
  <div class="row">
    <button type="submit">提交</button>
  </div>
</form>
<p>{{ rigisterForm.status }}</p>

可以使用rigisterForm.get(formControlName).value获取每个控件的值,

rigisterForm.value可以获取整个表单的数据

rigisterForm.status可以获取表单验证是否通过,是表单所有的验证规则。

3.表单验证

3. 1模板驱动验证

为了往模板驱动表单中添加验证机制,你要添加一些验证属性,就像原生的 HTML 表单验证器。 Angular 会用指令来匹配这些具有验证功能的指令。

每当表单控件中的值发生变化时,Angular 就会进行验证,并生成一个验证错误的列表(对应着 INVALID 状态)或者 null(对应着 VALID 状态)。

eg:

<input id="name" name="name" class="form-control" 
      required minlength="4" appForbiddenName="bob"
      [(ngModel)]="hero.name" #name="ngModel" >

<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.forbiddenName">
    Name cannot be Bob.
  </div>

</div>
3.2响应式表单验证

在响应式表单中,真正的源码都在组件类中。不应该通过模板上的属性来添加验证器,而应该在组件类中直接把验证器函数添加到表单控件模型上(FormControl)。然后,一旦控件发生了变化,Angular 就会调用这些函数。

验证器函数

有两种验证器函数:同步验证器和异步验证器。

  • 同步验证器函数接受一个控件实例,然后返回一组验证错误或 null。你可以在实例化一个 FormControl 时把它作为构造函数的第二个参数传进去。
  • 异步验证器函数接受一个控件实例,并返回一个承诺(Promise)或可观察对象(Observable),它们稍后会发出一组验证错误或者 null。你可以在实例化一个 FormControl 时把它作为构造函数的第三个参数传进去。

上面2.2中最后一个例子使用的就是响应式表单验证。

自定义验证器,2.2最后一个例子就有两个自定义验证器,mobileValidator和equalValidator分别验证手机号和密码,自定义验证器代码如下:

import {FormGroup, FormControl } from '@angular/forms';
export function mobileValidator(control: FormControl): any {
    const myreg = /^1[0-9]{10}$/;
    const valid = myreg.test(control.value);
    console.log('mobile的校验值为' + valid);
    return valid ? null : { mobile: true };
  }
  export function equalValidator(group: FormGroup): any {
    const pass = group.get('password') as FormControl;
    const pconfirm = group.get('pconfirm') as FormControl;
    const valid: boolean = (pass.value === pconfirm.value);
    console.log('密码校验结果' + valid);
    return valid ? null : { equal: true };
  }

自定义表单添加到响应式表单中很简单,直接把这个函数放到FormControl就行了。

添加到模板驱动表单

在模板驱动表单中,你不用直接访问 FormControl 实例。所以不能像响应式表单中那样把验证器传进去,而应该在模板中添加一个指令。

Angular 表单验证是一种在 Web 应用程序中对用户输入进行验证的方法。它可以防止用户在提交表单之前输入不正确的数据。在 Angular 中,表单验证是通过构建验证器函数并将其应用于表单控件来完成的。以下是一个简单的例子,演示如何在 Angular 中应用表单验证: 1. 在 HTML 模板中定义表单: ```html <form (ngSubmit)="onSubmit()" #myForm="ngForm"> <label> Name: <input type="text" name="name" ngModel required> </label> <label> Email: <input type="email" name="email" ngModel required email> </label> <button type="submit" [disabled]="!myForm.form.valid">Submit</button> </form> ``` 2. 在组件中定义验证器函数: ```typescript import { Component } from '@angular/core'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.css'] }) export class FormComponent { myForm: FormGroup; constructor(private fb: FormBuilder) { this.myForm = this.fb.group({ name: ['', Validators.required], email: ['', [Validators.required, Validators.email]] }); } onSubmit() { console.log(this.myForm.value); } } ``` 在上面的代码中,我们使用 `FormBuilder` 创建了一个名为 `myForm` 的表单,并添加了两个控件:`name` 和 `email`。`name` 控件是必填的,而 `email` 控件则需要符合电子邮件格式。在 `onSubmit` 方法中,我们可以访问表单的值,并进行进一步的处理。 值得注意的是,为了让表单控件与模板中的 `ngModel` 指令进行绑定,我们需要在组件中导入 `FormsModule` 模块。在模板中,我们还使用了 Angular 的模板语法,如 `ngSubmit` 事件和 `[disabled]` 属性,来控制表单的行为。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值