Angular学习笔记之-11.表单

Angular 表单简介

响应式表单和模板驱动表单以不同的方式处理和管理表单数据。每种方法都有各自的优点。

1.响应式表单提供对底层表单对象模型直接、显式的访问。它们与模板驱动表单相比,更加健壮:它们的可扩展性、可复用性和可测试性都更高。如果表单是你的应用程序的关键部分,或者你已经在使用响应式表单来构建应用,那就使用响应式表单。

2.模板驱动表单依赖模板中的指令来创建和操作底层的对象模型。它们对于向应用添加一个简单的表单非常有用,比如电子邮件列表注册表单。它们很容易添加到应用中,但在扩展性方面不如响应式表单。如果你有可以只在模板中管理的非常基本的表单需求和逻辑,那么模板驱动表单就很合适。

响应式表单

对于响应式表单,你可以直接在组件类中定义表单模型。[formControl] 指令会通过内部值访问器来把显式创建的 FormControl 实例与视图中的特定表单元素联系起来。

 import { Component } from '@angular/core';
 import { FormControl } from '@angular/forms';

  @Component({
  selector: 'app-forms-reactive',
  template:
  ` 
      <h1>app-forms-reactive</h1> 
      Favorite Color: <input type="text" [formControl]="favoriteColorControl">
  
  `,
  })
  export class FormsReactiveComponent {
  favoriteColorControl = new FormControl('');
  }

建立模板驱动表单

在模板驱动表单中,表单模型是隐式的,而不是显式的。指令 NgModel 为指定的表单元素创建并管理一个 FormControl 实例。

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

 @Component({
  selector: 'app-forms-template-driven',
  template: `
      <h1>app-forms-template-driven</h1>
      Favorite Color: <input type="text" [(ngModel)]="favoriteColor" />
  `,
  })
  export class FormsTemplateDrivenComponent {
      _favoriteColor = '2222';
      get favoriteColor() {
          return this._favoriteColor;
      }

      set favoriteColor(value) {
          console.log('value:', value);
          this._favoriteColor = value;
      }
  }

响应式表单详解

添加基础表单控件

使用表单控件有三个步骤。

1.在你的应用中注册响应式表单模块。该模块声明了一些你要用在响应式表单中的指令。

2.生成一个新的 FormControl 实例,并把它保存在组件中。

3.在模板中注册这个 FormControl

代码示例

  /* name-editor.component.ts */

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

  @Component({
  selector: 'app-name-editor',
  templateUrl: './name-editor.component.html',
  styleUrls: ['./name-editor.component.css'],
  })
  export class NameEditorComponent implements OnInit {
      name = new FormControl('kwok');
      
      ngOnInit(): void {
          /* 监听值得变化 */
          this.name.valueChanges.subscribe((res) => {
          console.log('name-change:', res);
          });
      }

      /* 替换表单控件的值 */ 
      updateName() {  
          this.name.setValue('Nancy');
      }
  }
  <!--  name-editor.component.html  -->

  <label>
      Name:
  <input type="text" [formControl]="name" />
  </label>

  <!--  显示表单控件的值  -->
  <p>Value: {{ name.value }}</p>

  <p>
  <button (click)="updateName()">Update Name</button>
  </p>
  
把表单控件分组

要将表单组添加到此组件中,请执行以下步骤。

1.创建一个 FormGroup 实例。

2.把这个 FormGroup 模型关联到视图。

3.保存表单数据。

代码示例

  /* profile-editor.component.ts */

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

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


  profileForm = new FormGroup({
      firstName: new FormControl(''),
      lastName: new FormControl(''),
      /* 创建嵌套的表单组 */
      address: new FormGroup({
          street: new FormControl(''),
          city: new FormControl(''),
          state: new FormControl(''),
          zip: new FormControl(''),
      }),
  });


  
  constructor(private fb: FormBuilder) { }


  ngOnInit(): void {
      this.profileForm.valueChanges.subscribe((res) => {
      console.log('res:', res);
      });
  }

  onSubmit() {
      console.log('this.profileForm:', this.profileForm.value);
  }

  /* 更新部分数据模型 */
  updateProfile() {
      // this.profileForm.patchValue({
      //   firstName: 'Nancy',
      //   address: {
      //     street: '123 Drew Street',
      //   },
      // });
      this.profileForm.setValue({
      firstName: 'Nancy',
      lastName: '',
      address: {
          street: '123 Drew Street',
          city: '',
          state: '',
          zip: '',
      },
      });
  }
  }
 <!--  profile-editor.component.html  -->

<form [formGroup]="profileForm">
<label>
    firstName:
    <input type="text" formControlName="firstName" />
</label>
<br />

<label>
    lastName:
    <input type="text" formControlName="lastName" />
</label>
<br />

    <form formGroupName="address">
        <label>
        street:
        <input type="text" formControlName="street" />
        </label>
        <br />

        <label>
        city:
        <input type="text" formControlName="city" />
        </label>
        <br />

        <label>
        state:
        <input type="text" formControlName="state" />
        </label>
        <br />

        <label>
        zip:
        <input type="text" formControlName="zip" />
        </label>
        <br />
    </form>
</form>
<button type="submit" [disabled]="!profileForm.valid" (click)="onSubmit()">
Submit
</button>
<p>
<button (click)="updateProfile()">Update Profile</button>
</p>
<p>Value: {{ profileForm.value | json }}</p>

使用 FormBuilder 服务生成控件

通过下列步骤可以利用这项服务。

1.导入 FormBuilder 类。

2.注入这个 FormBuilder 服务。

3.生成表单内容

代码示例

   /* profile-editor.component.ts */

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

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

    profileForm = this.fb.group({
        firstName: [''],
        lastName: [''],
        address: this.fb.group({
        street: [''],
        city: [''],
        state: [''],
        zip: ['']
        }),
    });
    
    constructor(private fb: FormBuilder) { }


    ngOnInit(): void {
        this.profileForm.valueChanges.subscribe((res) => {
        console.log('res:', res);
        });
    }

    onSubmit() {
        console.log('this.profileForm:', this.profileForm.value);
    }

    updateProfile() {
        // this.profileForm.patchValue({
        //   firstName: 'Nancy',
        //   address: {
        //     street: '123 Drew Street',
        //   },
        // });
        this.profileForm.setValue({
        firstName: 'Nancy',
        lastName: '',
        address: {
            street: '123 Drew Street',
            city: '',
            state: '',
            zip: '',
        },
        });
    }
    }

 <!--  profile-editor.component.html  -->

<form [formGroup]="profileForm">
 <label>
     firstName:
     <input type="text" formControlName="firstName" />
 </label>
 <br />

 <label>
     lastName:
     <input type="text" formControlName="lastName" />
 </label>
 <br />

 <form formGroupName="address">
     <label>
     street:
     <input type="text" formControlName="street" />
     </label>
     <br />

     <label>
     city:
     <input type="text" formControlName="city" />
     </label>
     <br />

     <label>
     state:
     <input type="text" formControlName="state" />
     </label>
     <br />

     <label>
     zip:
     <input type="text" formControlName="zip" />
     </label>
     <br />
 </form>
 </form>
 <button type="submit" [disabled]="!profileForm.valid" (click)="onSubmit()">
 Submit
 </button>
 <p>
 <button (click)="updateProfile()">Update Profile</button>
 </p>
 <p>Value: {{ profileForm.value | json }}</p>
 
验证表单输入

使用下列步骤添加表单验证。

1.在表单组件中导入一个验证器函数。

2.把这个验证器添加到表单中的相应字段。

3.添加逻辑来处理验证状态。

代码示例

   /* profile-editor.component.ts */

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

   @Component({
   selector: 'app-profile-editor',
   templateUrl: './profile-editor.component.html',
   styleUrls: ['./profile-editor.component.css'],
   })
   export class ProfileEditorValidatingComponent implements OnInit {
   profileForm = this.fb.group({
       firstName: ['', Validators.required],
       lastName: [''],
       address: this.fb.group({
       street: [''],
       city: [''],
       state: [''],
       zip: [''],
       }),
   });

   constructor(private fb: FormBuilder) {}

   ngOnInit(): void {
       this.profileForm.valueChanges.subscribe((res) => {
       console.log('res:', res);
       });
   }

   onSubmit() {
       console.log('this.profileForm:', this.profileForm.value);
   }

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

  <!--  profile-editor.component.html  -->

  <form [formGroup]="profileForm">
   <label>
       firstName:
       <input type="text" formControlName="firstName" />
   </label>
   <br />

   <label>
       lastName:
       <input type="text" formControlName="lastName" />
   </label>
   <br />

   <form formGroupName="address">
       <label>
       street:
       <input type="text" formControlName="street" />
       </label>
       <br />

       <label>
       city:
       <input type="text" formControlName="city" />
       </label>
       <br />

       <label>
       state:
       <input type="text" formControlName="state" />
       </label>
       <br />

       <label>
       zip:
       <input type="text" formControlName="zip" />
       </label>
       <br />
   </form>
   </form>
   <button type="submit" [disabled]="!profileForm.valid" (click)="onSubmit()">
   Submit
   </button>
   <p>
   <button (click)="updateProfile()">Update Profile</button>
   </p>
   <p>Value: {{ profileForm.value | json }}</p>
   <p>Form Status: {{ profileForm.status }}</p>
创建动态表单

使用下列步骤添加表单验证。

1.导入 FormArray 类。

2.定义一个 FormArray 控件。

3.使用 getter 方法访问 FormArray 控件。

4.在模板中显示这个表单数组。

代码示例

  /* profile-editor.component.ts */

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

@Component({
selector: 'app-profile-editor',
templateUrl: './profile-editor.component.html',
styleUrls: ['./profile-editor.component.css'],
})
export class ProfileEditorDynamicComponent implements OnInit {
profileForm = this.fb.group({
  firstName: ['', Validators.required],
  lastName: [''],
  address: this.fb.group({
  street: [''],
  city: [''],
  state: [''],
  zip: [''],
  }),
  aliases: this.fb.array([
  this.fb.control('')
  ])
});

get aliases() {
  return this.profileForm.get('aliases') as FormArray;
}


constructor(private fb: FormBuilder) {}

ngOnInit(): void {
  this.profileForm.valueChanges.subscribe((res) => {
  console.log('res:', res);
  });
}

onSubmit() {
  console.log('this.profileForm:', this.profileForm.value);
}

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

addAlias() {
  this.aliases.push(this.fb.control(''));
}
}


  <!--  profile-editor.component.html  -->

 <form [formGroup]="profileForm">
    <label>
        firstName:
        <input type="text" formControlName="firstName" />
    </label>
    <br />

    <label>
        lastName:
        <input type="text" formControlName="lastName" />
    </label>
    <br />

    <form formGroupName="address">
        <label>
        street:
        <input type="text" formControlName="street" />
        </label>
        <br />

        <label>
        city:
        <input type="text" formControlName="city" />
        </label>
        <br />

        <label>
        state:
        <input type="text" formControlName="state" />
        </label>
        <br />

        <label>
        zip:
        <input type="text" formControlName="zip" />
        </label>
        <br />
    </form>

    <div formArrayName="aliases">
        <h3>Aliases</h3>
        <button (click)="addAlias()">Add Alias</button>

        <div *ngFor="let alias of aliases.controls; let i = index">
        <!-- The repeated alias template -->
        <label>
            Alias:
            <input type="text" [formControlName]="i" />
        </label>
        </div>
    </div>
    </form>
    <button type="submit" [disabled]="!profileForm.valid" (click)="onSubmit()">
    Submit
    </button>
    <p>
    <button (click)="updateProfile()">Update Profile</button>
    </p>
    <p>Value: {{ profileForm.value | json }}</p>
    <p>Form Status: {{ profileForm.status }}</p>
响应式表单 API 汇总

官网传送门