NgForm学习笔记

2,101 阅读7分钟

从废弃的 ngForm 选择器迁移过来监听表单提交设置更新选项NgForm与NgModelngModel[ngModel][(ngModel)]参考文献

NgForm 创建一个顶级的 FormGroup 实例,并把它绑定到一个表单,以跟踪表单的聚合值及其验证状态。

官方文档说明:

只要你导入了 FormsModule,该指令就会默认在所有

标签上生效。你不需要再添加任何特殊的选择器。

你可以以 ngForm 作为 key 把该指令导出到一个局部模板变量(如 #myForm="ngForm")。这是可选的,但很有用。 来自本指令背后的 FormGroup 实例的很多属性,都被复制到了指令自身,所以拿到一个对该指令的引用就可以让你访问此表单的聚合值和验证状态, 还有那些用户交互类的属性,比如 dirtytouched

如果需要,还可以监听该指令的 ngSubmit 事件,以便当用户触发了一次表单提交时得到通知。发出 ngSubmit 事件时,会携带原始的 DOM 表单提交事件。

在模板驱动表单中,所有 标签都会自动应用上 `NgForm` 指令。 如果你只想导入 `FormsModule` 而不想把它应用于某些表单中,比如,要想使用 HTML5 验证,你可以添加 `ngNoForm` 属性, 这样标签就不会在 上创建 NgForm 指令了。 在响应式表单中,则不需要用 ngNoForm,因为 NgForm 指令不会自动应用到 ` 标签上,你只要别主动添加formGroup` 指令就可以了。

从废弃的 ngForm 选择器迁移过来

ngForm 元素选择器的支持已经在 Angular v6 中废弃,并将在 Angular v9 中移除。

之所以弃用它,是我们要让所有选择器都跟其它核心 Angular 选择器保持统一,而元素选择器通常写作中线格式。

已废弃的写法:

<ngForm #myForm="ngForm">

以后的写法:

<ng-form #myForm="ngForm">

监听表单提交

下面的示例显示如何从“ ngSubmit”事件捕获表单值。

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

@Component({
  selector'example-app',
  template`
    <h2>Listening for form submission</h2>

    <form  (ngSubmit)="onSubmit(f)" #f="ngForm" novalidate >
      <label>First Name: <input name="first" ngModel required #first="ngModel" /></label>
      <br>
      <label>Last Name: <input name="last" ngModel /></label>
      <br>
      <button>Submit</button>
    </form>

    <div>
      <p>First name value: {{ first.value }}</p>
      <p>First name valid: {{ first.valid }}</p>
      <p>Form value: {{ f.value | json }}</p>
      <p>Form valid: {{ f.valid }}</p>
    </div>

    <div [hidden]="!f.valid">
      <p>{{submitMessage }}</p>
    </div>
  `
,
})
export class SimpleFormComp {
  submitMessage = '';
  onSubmit(f: NgForm) {
    console.log(f.value);
    console.log(f.valid);
    this.submitMessage = '数据已提交';
  }
}

页面测试:

设置更新选项

自 Angular5 之后,增加了这么一个新特性:updateOn blur或submit

表单字段或整个表单新增了选项 updateOn,它可以让 Angular 仅在 blur 或 submit 事件时检查有效性,而不是默认的变更事件,这有助于提高性能。

例如,给定一个模板驱动的表单,如下所示:

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

@Component({
  selector'example-app',
  template`
     <form #newUserForm="ngForm" (ngSubmit)="onSubmit(newUserForm)">

      <label for="user-name">User Name:</label>
      <input type="text" placeholder="User name"
             required maxlength="25" id="user-name"
             [(ngModel)]="userName" name="userName">

      <button type="submit" [disabled]="!newUserForm.form.valid">
        Register
      </button>
    </form>
  `
,
})
export class SimpleFormComp {
  onSubmit(f: NgForm) {
    console.log(f.value);  // { first: '', last: '' }
    console.log(f.valid);  // false
  }
}

页面测试:

注意观察 html 代码中的 button 标签,当开始在输入框输入内容时,button 标签的 disabled 属性立刻消失,通俗点讲就是表单时刻都在做有效性检查。

如果你现在想输入内容,让 Angular 仅在输入触发 blur 事件时才进行有效性检查:

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

@Component({
  selector'example-app',
  template`
     <form #newUserForm="ngForm" (ngSubmit)="onSubmit(newUserForm)">

      <label for="user-name">User Name:</label>

      <input type="text" placeholder="User name"
          required maxlength="5" id="user-name"
          [(ngModel)]="userName" name="userName"
          [ngModelOptions]="{updateOn: 'blur'}" />

      <button type="submit" [disabled]="!newUserForm.form.valid">
        Register
      </button>
    </form>
  `
,
})
export class SimpleFormComp {
  onSubmit(f: NgForm) {
    console.log(f.value);  // { first: '', last: '' }
    console.log(f.valid);  // false
  }
}

页面测试:

当输入完数据之后,鼠标焦点事件改变之后,button 标签才会启用。

对于上述对 input 标签的修改,也可以一次性对整个表单应用。

<form #newUserForm="ngForm"
      (ngSubmit)="onSubmit(newUserForm)"
      [ngFormOptions]="{updateOn: 'blur'}">

  ...
</form>

NgForm与NgModel

NgForm 中关于 NgModel 的使用有三种用法,分为 ngModel、[ngModel]和[(ngModel)]。

ngModel

如果单独使用 ngModel,且没有为其赋值的话,它会在其所在的 ngForm.value 对象上添加一个 property,此 property 的 key 值为 ngModel 所在组件设置的 name 属性的值:

<form #f="ngForm">
  <input type="text" ngModel name="firstField">
  <br>
  <span>{{ f.controls['firstField']?.value }}</span>
  <p>{{f.value | json }}</p>    //{ "firstField": "" }
</form>

单独使用 ngModel 时,如果没有为 ngModel 赋值的话,则必须存在 name 属性

[ngModel]

ngForm 中绑定的 property 的 key 为 ngModel 所在组件设置的 name 属性的值,value 值我们可以赋予默认值。此时需要使用单向数据绑定的格式了,也就是[ngModel]:

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

@Component({
  selector'example-app',
  template`
    <form #ff="ngForm">
      <input type="text" name="firstField" [ngModel]="model.firstField" placeholder='Input your userName' >
      <p>{{ff.value | json }}</p>
      <p>{{model | json}}</p>
    </form>
  `
,
})
export class SimpleFormComp {
    model = {
    firstField'hresh'
  };
}

页面测试:

这里我们使用了单向数据绑定的特点,可以为 ngForm.value 添加一个带有初始值的 property。

[(ngModel)]

上述的单向数据绑定在单纯地提供初始值很有用,不过总是有些场景需要将用户输入体现在我们的 model 上,此时就需要双向数据绑定了,也即[(ngModel)]:

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

@Component({
  selector'example-app',
  template`
    <form #ff="ngForm">
      <input type="text" name="firstField" [(ngModel)]="model.firstField" placeholder='Input your userName' >
      <p>{{ff.value | json }}</p>
      <p>{{model | json}}</p>
    </form>
  `
,
})
export class SimpleFormComp {
    model = {
    firstField'hresh'
  };
}

页面测试:

这里我们不仅为 ngForm.value 添加了一个带有初始值的 property,还能实现 Model 和 View 层的联动。

参考文献

Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]

[译]Angular 5:升级和新功能的总结