如何在 AngularJS 中使用“ng-model”的示例

⚡ 智能摘要

AngularJS 中的 ng-model 将输入控件直接绑定到 $scope 上的属性,保持ping 视图和模型双向同步。以下各节将介绍该属性、三个工作示例以及初学者最常遇到的错误。

  • 🔗 双向装订: ng-model 将用户输入推送到 $scope 属性,并将控制器更改自动推送回控件。
  • 📝 文本区域绑定: 将多行字符串绑定到文本区域,并使用 \n 转义序列强制在渲染值中换行。
  • ☑️ 复选框状态: 使用 ng-model 绑定的复选框存储一个布尔值,因此 true 表示选中该复选框,false 表示未选中。
  • 📋 下拉列表: 使用 ng-options 填充选择元素,并将所选项目绑定到单独的模型属性。
  • ⚠️ 常见故障: 将下拉列表绑定到提供其选项文本的同一对象上,会在第一次选择时覆盖该对象。
  • 🛠️ 验证钩子: ng-model 添加了 ng-pristine、ng-dirty、ng-valid 和 ng-invalid 类,用于驱动条件样式和表单检查。

AngularJS 中的 ng-model 是什么?

ng-model 是 AngularJS 中的一个指令,它代表模型,其主要目的是将“视图”绑定到“模型”。用户在控件中输入的任何内容都会直接写入到视图的一个属性中。 $scope控制器写入该属性的任何内容都会直接推送回控件。

例如,假设您想向最终用户展示一个如下所示的简单页面,该页面要求用户在文本框中输入“名字”和“姓氏”。然后,您希望确保将用户输入的信息存储在您的数据模型中。

您可以使用 ng-model 指令将文本框中的“名字”和“姓氏”字段映射到您的数据模型。该指令将确保“视图”中的数据和“模型”中的数据始终保持同步,而无需编写任何事件处理代码。

⚠️ 版本说明: AngularJS(1.x 分支)已于 2021 年 12 月 31 日停止维护,不再接收安全补丁。以下示例仍然可以运行,但在现代 Angular 中,相同的双向绑定需要这样编写: [(ngModel)] 并且需要 FormsModule。

ng-model 属性

如上文所述,ng-model 属性用于将模型中的数据绑定到呈现给用户的视图。

ng-model 属性用于:

  1. 将视图中的输入框、文本区域和选择框等控件绑定到模型中。
  2. 提供验证行为——例如,可以向文本框添加验证,以便只能输入数字字符。
  3. 保持控件的状态。所谓状态,是指控件和数据始终保持同步:如果数据的值发生变化,控件中的值也会自动变化,反之亦然。
  4. 将该状态暴露为 CSS 类。AngularJS 添加 ng-pristine, ng-dirty, ng-validng-invalid 每个带有 ng-model 的控件都会应用此规则,这使得表单的条件样式设置变得简单。

了解了该属性之后,下一步是将其应用于您最常遇到的三种控件类型。

如何使用 ng-model

1)文本区域

文本区域标签用于定义多行文本输入控件。文本区域可以容纳无限数量的字符,并且文本以固定宽度的字体呈现。

现在我们来看一个简单的例子,了解如何将 ng-model 指令添加到文本区域控件。在这个例子中,我们将展示如何将多行字符串从控制器传递到视图,并将该值附加到文本区域控件。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Registration</title>
    <script src="https://code.angularjs.org/1.8.3/angular.js"></script>
</head>
<body>
<h1>Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoCtrl">
    <form>
        Topic Description:<br><br>
        <textarea rows="4" cols="50" ng-model="pDescription"></textarea>
    </form>
</div>

<script>
    var app = angular.module('DemoApp', []);
    app.controller('DemoCtrl', function($scope) {
        $scope.pDescription = "This topic looks at how Angular JS works \nModels in Angular JS";
    });
</script>
</body>
</html>

Code 说明:

  1. ng-model 指令 附加名为“p”的成员变量Descript将“ion”添加到“textarea”控件。“pDescript“ion”变量保存着传递给文本区域控件的文本。 rows="4"cols="50" 属性的作用是调整控件的大小,以便正确显示多行文本。
  2. 成员变量“p”Description”被赋予一个多行值。 \n 字符串中的转义序列会在文本区域渲染文本时强制将其显示在第二行。

输出:

从输出结果可以看出,控制器中分配的多行文本显示在文本区域控件中,并恰好在两行之间分割。 \n 坐。

2)输入元素

ng-model 指令也适用于普通的输入元素。下面我们同时绑定一个文本框和两个复选框,这样你就可以看到 ng-model 如何并排处理字符串值和布尔值。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Registration</title>
    <script src="https://code.angularjs.org/1.8.3/angular.js"></script>
</head>
<body>
<h1>Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoCtrl">
    <form>
        Topic Description:<br><br>
        Name : <input type="text" ng-model="pname"><br>
        Topic :<br>
        <input type="checkbox" ng-model="Topic.Controller">Controller<br>
        <input type="checkbox" ng-model="Topic.Models">Models
    </form>
</div>

<script>
    var app = angular.module('DemoApp', []);
    app.controller('DemoCtrl', function($scope) {
        $scope.pname = "Guru99";

        $scope.Topic = {
            Controller: true,
            Models: false
        };
    });
</script>
</body>
</html>

Code 说明:

  1. ng-model 指令将成员变量“pname”附加到文本输入控件,以及属性 Topic.ControllerTopic.Models 对两个复选框控件。
  2. 在控制器中,“pname”被赋予字符串“Guru99”,并且“Topic”对象被赋予了两个布尔成员。绑定到ng-model的复选框始终读取和写入布尔值,这就是为什么 true 将复选框渲染为选中状态 false 这样就很清楚了。

输出:

从输出来看,

  • 可以清楚地看到,分配给 pname 变量是“Guru99“。
  • 由于第一个边界值是 true“控制器”复选框已选中。同样,由于第二个值是 false“模型”复选框未选中。

3)从下拉列表中选择元素

ng-model 指令也可以应用于 select 元素,以便将用户选择的项目存储在模型中。

这里我们将有一个文本输入框,用于输入名称“Guru99”,以及一个包含两个列表项的选择列表:“控制器”和“模型”。

⚠️更正: 上面的截图显示了原始列表,其中 select 元素绑定到了同一个位置。 Topics 提供选项文本的对象。用户选择选项后,AngularJS 会覆盖该对象。 Topics 选中字符串后,两个选项都会消失。下面的修正列表将列表保存在一个属性中,将选择保存在另一个属性中,并使用 ng-options 建立列表。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Event Registration</title>
    <script src="https://code.angularjs.org/1.8.3/angular.js"></script>
</head>
<body>
<h1>Guru99 Global Event</h1>

<div ng-app="DemoApp" ng-controller="DemoCtrl">
    <form>
        Topic Description:<br><br>
        Name : <input type="text" ng-model="pName"><br>
        Topic :<br>
        <!-- Topics holds the list; selectedTopic holds the choice -->
        <select ng-model="selectedTopic" ng-options="t for t in Topics"></select>
    </form>
</div>

<script>
    var app = angular.module('DemoApp', []);
    app.controller('DemoCtrl', function($scope) {
        $scope.pName = "Guru99";

        $scope.Topics = ["Controller", "Models"];
        $scope.selectedTopic = $scope.Topics[0];
    });
</script>
</body>
</html>

Code 说明:

  1. 文本输入绑定到 pName并且选择元素绑定到 selectedTopic因为 select 元素有自己的模型属性,所以选择一个选项永远不会影响列表本身。
  2. Topics 数组包含两个值:“Controller”和“Models”。 ng-options 表达式遍历该数组,并为每个条目渲染一个选项,因此添加第三个主题不需要更改标记。
  3. selectedTopic 预设为第一个条目,这使得下拉菜单能够以合理的默认值打开,而不是空白行。

输出:

从输出结果可以看出,分配给该值 pName 变量是“Guru99”,选择控件提供“控制器”和“模型”选项。除了示例之外,绑定有时确实会拒绝更新,其原因值得了解。

为什么 ng-model 绑定有时会失败

大多数报告的 ng-model 问题并非 AngularJS 中的错误,而是作用域和原始类型工作方式导致的后果。

典型的例子是将绑定放在一个会创建子作用域的指令内部,例如 ng-重复ng-if 或 ng-switch。编写 ng-model="name" 这会在其子作用域上创建一个影子副本,因此父作用域永远不会看到编辑内容。改为绑定到对象的属性—— ng-model="user.name" ——确保所有作用域都指向同一个引用。这就是为什么经验丰富的 AngularJS 开发人员坚持在每个 ng-model 表达式中都使用点号的原因。

其余大部分原因归结于另外两个方面:

  • 缺少控制器或模块: 如果 ng-app 或 ng-controller 拼写错误,绑定将静默地不渲染任何内容,而不是引发错误。
  • 值在 AngularJS 之外被更改: 来自 jQuery 处理程序或 setTimeout 回调函数的值会落在摘要周期之外,因此视图不会刷新,直到…… $scope.$apply() 运行。

检查这三件事可以解决绝大多数看似不起作用的绑定问题。

常见问题

ng-bind 是单向的:它将模型值写入元素。ng-model 是双向的,并且仅适用于表单控件,因此用户输入既可以流入模型,也可以流出模型。

添加 ng-model-options,例如 ng-model-options=”{ debounce: 500 }”。AngularJS 会在最后一次按键后等待半秒钟再更新模型,这对于触发请求的搜索框非常有用。

基本上是这样。AI 助手会将 `ng-model` 重写为 `[(ngModel)]`,并添加 `FormsModule` 导入。响应式表单、自定义解析器和 `$formatters` 管道仍然需要人工审核,因为 Angular 对它们的建模方式截然不同。

AI 工具会快速检查常见错误:子作用域内的原始类型绑定、拼写错误的控制器名称以及在摘要周期之外赋值。这些错误都会导致静默失败,而不是控制台错误。

只有 type="number" 的输入才会被解析为数值。type="text" 的控件始终返回字符串,因此使用 === 进行比较会失败。请显式转换或切换输入类型。

总结一下这篇文章: