Angular 4.x ngModel 双向绑定原理揭秘

一直以来都没有去深入探究Angular,只是熟练运用。真要被问起来,很多关于angular的理论知识都回答不上来。感觉上学背书的能力已经丧失的差不多了。只能以这样的方式搜集整理出来。

在 Angular 4.x 中对于使用 Template-Driven 表单场景,如果需要实现表单数据绑定。我们就需要引入 ngModel 指令。该指令用于基于 domain 模型,创建 FormControl 实例,并将创建的实例绑定到表单控件元素上。

ngModel 使用示例

app.component.ts

@Component({
  selector: 'exe-app',
  template: `
   <form novalidate #f="ngForm">
      Name: <input type="text" name="username" ngModel>
   </form>
   {{ f.value | json }}
  `,
})
export class AppComponent implements OnInit { }

在 <form> 表单中使用 ngModel 时,我们需要设置一个 name 属性,以便该控件可以使用该名称在表单中进行注册。

单向绑定 – [ngModel]

app.component.ts

@Component({
  selector: 'exe-app',
  template: `
   <form novalidate #f="ngForm">
      Name: <input type="text" name="username" [ngModel]="user.username">
   </form>
   {{ user | json }}
  `,
})
export class AppComponent implements OnInit {
  user: { username: string };

  ngOnInit() {
    this.user = { username: 'Semlinker' };
  }
}
双向绑定 – [(ngModel)]

app.component.ts (表单中应用)

@Component({
  selector: 'exe-app',
  template: `
   <form novalidate #f="ngForm">
      Name: <input type="text" name="username" [(ngModel)]="user.username">
   </form>
   {{ user | json }}
  `,
})
export class AppComponent implements OnInit {
  user: { username: string };

  ngOnInit() {
    this.user = { username: 'Semlinker' };
  }
}

app.component.ts (单独应用)

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

@Component({
  selector: 'exe-app',
  template: `
    <input name="username" [(ngModel)]="username">
    {{username}}
  `,
})
export class AppComponent {
  username: string;
}
ngModelOptions – [ngModelOptions]

当你在使用 ngModel 时未设置 name 属性,如下所示:

<form novalidate #f="ngForm">
   Name: <input type="text" [(ngModel)]="user.username">
</form>

当你运行时,浏览器控制台将会抛出以下异常信息:

Error: If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions.

以上异常信息告诉我们,如果在表单标签中使用 ngModel,则必须设置 name 属性,或者在 ngModelOptions 中必须将表单控件定义为 “standalone”。依据上述异常信息,我们做如下调整:

<form novalidate #f="ngForm">
   Name: <input type="text" [(ngModel)]="user.username" 
              [ngModelOptions]="{standalone: true}">
</form>

接下来我们看一下 ngModelOptions 支持的对象类型:

@Input('ngModelOptions') options: {name?: string, standalone?: boolean};
禁用控件 – disabled
<form novalidate #f="ngForm">
   Name: <input type="text" name="username" 
            [(ngModel)]="user.username" disabled="true">
</form>
监听 ngModelChange 事件 – (ngModelChange)

app.component.ts

@Component({
  selector: 'exe-app',
  template: `
   <form novalidate #f="ngForm">
      Name: <input type="text" name="username" (ngModelChange)="userNameChange($event)"
        [(ngModel)]="user.username">
   </form>
   {{ user | json }}
  `,
})
export class AppComponent implements OnInit {
  user: { username: string };

  ngOnInit() {
    this.user = { username: 'Semlinker' };
  }

  userNameChange(name: string) {
    console.log(name);
  }
}
获取关联的 NgModel 对象

app.component.ts

@Component({
  selector: 'exe-app',
  template: `
   <form novalidate #f="ngForm">
      Name: <input type="text" name="username" #userName="ngModel"
        [(ngModel)]="user.username">
   </form>
   {{ userName.control | json }}
  `,
})
export class AppComponent implements OnInit {
  user: { username: string };

  ngOnInit() {
    this.user = { username: 'Semlinker' };
  }
}

通过使用 userName="ngModel" 方式,我们可以获取表单控件关联的 NgModel 对象,进而获取控件当前控件的相关信息,如控件的当前的状态或控件验证信息等。

完整示例

app.component.ts

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

@Component({
  selector: 'exe-app',
  template: `
    <form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
      <input name="first" ngModel required #first="ngModel">
      <input name="last" ngModel>
      <button>Submit</button>
    </form>
    <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>
  `,
})
export class AppComponent {
  onSubmit(f: NgForm) {
    console.log(f.value);  // { first: '', last: '' }
    console.log(f.valid);  // false
  }
}

Like (0)
Donate 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZEROZERO
Previous 2019年6月29日
Next 2019年7月3日

相关推荐

  • Angular环境搭建(Windows 10)

    目前前端开发正处于快速发展阶段,接触angular时,Angular 2刚刚发布,现在第五版也已经发布。由于刚开始没有系统的学习,导致工作中,经常捉襟见肘。现在把自己在工作中踩过的…

    2018年9月5日
    3.9K
  • Angular4.x ngModel 指令详解

    用过angular的前端工程师都知道,angular数据是可以双向绑定的。但是它为什么可以使数据双向绑定?原理又是什么?阅读这篇文章,来了解一下吧。

    2019年7月3日
    1.8K

发表回复

Please Login to Comment