首页
/ Angular 模板驱动表单读取控件值:从插值展示到组件类访问(ngModel 双向绑定实战)

Angular 模板驱动表单读取控件值:从插值展示到组件类访问(ngModel 双向绑定实战)

2026-09-07 15:00:15作者:姚月梅Lane

导读

在 Angular 中完成表单搭建后,下一步就是要读取用户输入到表单控件中的值。本篇指南基于 Angular 官方教程 Learn Angular 的“Getting form control values”练习(对应仓库教程步骤 16-form-control-values),完整讲解模板驱动表单下两种取值方式:在模板中用插值语法 {{ }} 展示输入值、在组件类中用 this 引用并编程式读取。学完后你将能够把 [(ngModel)] 绑定的数据呈现在页面上,也能在事件回调(如点击按钮、提交表单)中拿到实时的输入内容,并为过渡到响应式表单打好基础。

前置上下文:模板驱动表单与 ngModel 双向绑定

本练习紧接前一步“Forms Overview”(见 15-forms/README.md)。在使用模板驱动表单时,需要通过以下两步让输入框与组件属性建立数据连接:

  1. @angular/forms 导入 FormsModule 并加入组件的 imports 数组;
  2. <input> 上使用 [(ngModel)]="favoriteFramework" 语法完成双向绑定。

[(ngModel)] 这种“中括号包小括号”的写法俗称 banana-in-a-box(盒子里的香蕉),它本质上等价于 属性绑定(property binding)+ 事件绑定(event binding) 的组合,即:[ngModel] 把组件属性的值推送到输入框,(ngModelChange) 把输入框的新值回写到组件属性。正是因为这一层双向同步,用户每次键入内容,favoriteFramework 都会实时更新,后续所有取值方式才能拿到最新值。

方法一:在模板中展示输入控件的值(插值语法 {{ }}

读取表单控件值最简单的方式,就是像读取组件中任意一个 class 属性那样,在模板中使用插值语法 {{ }} 将值渲染到页面上。以下为带高亮的原始示例(第 5 行为 Framework: {{ favoriteFramework }} 插值渲染):

@Component({
  selector: 'app-user',
  template: `
    ...
    <p>Framework: {{ favoriteFramework }}</p>
    <label for="framework">
      Favorite Framework:
      <input id="framework" type="text" [(ngModel)]="favoriteFramework" />
    </label>
  `,
})
export class User {
  favoriteFramework = '';
}

这里的要点是:

  • favoriteFramework 只是组件类上的一个普通字符串属性,其默认值为 ''(空字符串);
  • 插值语法对表单绑定的属性同样适用,无需任何特殊 API;
  • Angular 的变更检测会自动保持 {{ favoriteFramework }} 与输入框内容同步,因此用户输入时,页面上的 Framework: 文本会随之实时刷新。

与本步骤配套的完整起始代码

仓库中该练习的起始工程位于 16-form-control-values/src/app/user.ts。可以看到初始化代码里已经包含了用户名展示、输入框双向绑定以及一个空的 showFramework() 方法,这正是本步骤要完成的改造对象:

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

@Component({
  selector: 'app-user',
  template: `
    <p>Username: {{ username }}</p>
    <p>Framework:</p>
    <label for="framework">
      Favorite Framework:
      <input id="framework" type="text" [(ngModel)]="favoriteFramework" />
    </label>
    <button (click)="showFramework()">Show Framework</button>
  `,
  imports: [FormsModule],
})
export class User {
  favoriteFramework = '';
  username = 'youngTech';

  showFramework() {}
}

对比可见:app.ts 作为根组件(selector 为 app-root)仅负责渲染 <app-user />,所有练习逻辑都集中在 user.ts 中,这也解释了为何该练习的配置文件把默认打开文件设为 src/app/user.ts

方法二:在组件类中访问输入控件的值(this 语法)

当需要在组件类内部引用输入框的值时(例如提交表单、拼接请求参数、做本地校验或弹窗提示),只需用 this 直接访问绑定的类属性即可。因为 [(ngModel)] 已经把输入框的值实时同步到了该属性上,组件类里读到的永远是当前最新的输入内容。

在模板上通过事件绑定把按钮点击连接到组件方法,然后在方法内用 this.favoriteFramework 读取值并弹出提示:

...
@Component({
  selector: 'app-user',
  template: `
    ...
    <button (click)="showFramework()">Show Framework</button>
  `,
  ...
})
export class User {
  favoriteFramework = '';
  ...

  showFramework() {
    alert(this.favoriteFramework);
  }
}

本步骤的标准答案

仓库提供了练习完成的参考答案,位于 16-form-control-values/answer/src/app/user.ts。它同时完成了“模板展示”和“类中读取”两步:第 8 行把 Framework: {{ favoriteFramework }} 渲染到页面,第 21-23 行在 showFramework() 中通过 alert(this.favoriteFramework) 弹出当前输入值:

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

@Component({
  selector: 'app-user',
  template: `
    <p>Username: {{ username }}</p>
    <p>Framework: {{ favoriteFramework }}</p>
    <label for="framework">
      Favorite Framework:
      <input id="framework" type="text" [(ngModel)]="favoriteFramework" />
    </label>
    <button (click)="showFramework()">Show Framework</button>
  `,
  imports: [FormsModule],
})
export class User {
  favoriteFramework = '';
  username = 'youngTech';

  showFramework() {
    alert(this.favoriteFramework);
  }
}

运行验证的行为是:在输入框中键入内容 → 页面上的 Framework: 文本实时更新 → 点击 “Show Framework” 按钮,弹出窗口显示与输入完全一致的字符串。

原理纵深:从 @angular/forms 源码看双向绑定的取值链路

为什么“在类里用 this 就能取到值”?这层机制由 @angular/forms 包中的 NgModel 指令提供。查阅仓库源码 packages/forms/src/directives/ng_model.ts 可以还原完整调用链:

  • 第 172 行 export class NgModel extends NgControl implements OnChanges, OnDestroy,即 NgModel 继承了表单控件抽象 NgControl,同时具备向模板公开值同步的能力;
  • 第 237 行 @Output('ngModelChange') update = new EventEmitter();,即 ngModelChange 事件输出,正是 [(ngModel)] 事件绑定那一半的真正实现(banana-in-a-box 拆开后对应 (ngModelChange));
  • 第 364 行 override viewToModelUpdate(newValue: any): void,该回调把视图(输入框)产生的新值通过事件输出回写到组件属性,从而让 this.favoriteFramework 始终持有最新输入;
  • 第 227-230 行的 @Input('ngModelOptions') options 还表明,值/有效性的更新时机 updateOn 默认是 'change',可配置为 'change' | 'blur' | 'submit'

因此,从数据流角度看本练习的两种取值方式殊途同归:插值表达式 {{ favoriteFramework }}this.favoriteFramework 读取的是同一份被 NgModel 双向绑定实时维护的组件属性,只是前者在模板层渲染、后者在类中编程式访问。

练习设计:编辑器内实时反馈

本练习在 Learn Angular 教程中以“编辑器(editor)”类型的任务呈现(见 config.json),默认只打开 src/app/user.ts。这种设计刻意让学习者把注意力集中在:仅靠修改模板插值、补全一个事件处理函数,就能同时验证“显示值”和“读取值”两条路径,直观感受模板驱动表单的声明式特性——不必手动监听事件或编写同步代码。

下一步:从模板驱动表单走向响应式表单

本练习完成了模板驱动表单从“绑定”到“取值”的闭环。教程紧接着引入 Angular 管理表单的另一种方式——响应式表单(见 17-reactive-forms/README.md)。在响应式表单中,取值逻辑从“组件属性 + 双向绑定”转变为以 FormControlFormGroup 为核心的编程式模型:模板中通过 [formGroup]formControlName 关联控件,读取值时使用 this.profileForm.value.name 这类结构,提交时借助 (ngSubmit) 事件配合 handleSubmit() 方法。可以对比看出:模板驱动表单的值天然与组件属性合一,取值极简;而响应式表单把控件状态集中收拢进 FormGroup,在大规模、动态化的表单场景下更便于程序化管理与校验。

小结

  • 展示输入值:模板中用插值 {{ favoriteFramework }},与渲染普通 class 属性完全一致;
  • 读取输入值:组件类中用 this.favoriteFramework,前提是输入框已通过 [(ngModel)] 建立双向绑定;
  • 底层支撑:NgModel 指令(ng_model.ts)通过 ngModelChange 输出与 viewToModelUpdate 回调,保证类属性与视图持续同步,使两条取值路径都能拿到实时数据;
  • 完整参考代码见 16-form-control-values/answer/src/app/user.ts,本步骤教程原文见 16-form-control-values/README.md,前一课建立双向绑定的过程见 15-forms/README.md

掌握这步之后,你就可以接着学习如何将表单值用于提交、校验,以及如何用响应式表单在组件类中全面接管控件状态。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525