AngularJS ng-model 指令

ng-model 是 AngularJS 中最重要的指令之一,用于实现双向数据绑定(Two-way Data Binding)。它将表单控件的值与作用域(Scope)中的属性绑定在一起,使得数据的变化能够自动同步。

一、基本概念

1. 什么是双向数据绑定

双向数据绑定意味着:

  • 视图 → 模型:用户在表单控件中输入数据时,自动更新作用域中的变量
  • 模型 → 视图:作用域中的变量变化时,自动更新表单控件的显示值
┌─────────────┐         ┌─────────────┐
│   视图      │  ←→    │   模型      │
│ (表单控件)  │         │ (Scope变量) │
└─────────────┘         └─────────────┘

2. 基本语法

<input type="text" ng-model="变量名">
// 控制器中
$scope.name = "张三";

二、基本用法

1. 文本输入框

<div ng-app="myApp" ng-controller="MyCtrl">
  <input type="text" ng-model="name" placeholder="请输入姓名">
  <p>你输入的是:{{ name }}</p>
</div>
angular.module('myApp').controller('MyCtrl', function($scope) {
  $scope.name = "初始值";
});

2. 文本域

<textarea ng-model="description" rows="4" cols="50"></textarea>
<p>描述:{{ description }}</p>

3. 数字输入

<input type="number" ng-model="age" min="0" max="120">
<p>年龄:{{ age }}</p>

三、不同表单控件的使用

1. 复选框

单个复选框
<input type="checkbox" ng-model="isChecked">
<p>状态:{{ isChecked ? "已选中" : "未选中" }}</p>
复选框组
<div ng-repeat="item in items">
  <input type="checkbox" 
         ng-model="item.selected"
         id="item-{{ $index }}">
  <label for="item-{{ $index }}">{{ item.name }}</label>
</div>

<p>已选:{{ items | filter:{selected:true} | json }}</p>
$scope.items = [
  { name: '选项1', selected: false },
  { name: '选项2', selected: false },
  { name: '选项3', selected: false }
];

2. 单选框

<input type="radio" ng-model="gender" value="male"><input type="radio" ng-model="gender" value="female"><input type="radio" ng-model="gender" value="other"> 其他

<p>性别:{{ gender }}</p>

注意:所有单选框的 ng-model 必须相同,value 不同。

3. 下拉框

基本用法
<select ng-model="selectedCity">
  <option value="">请选择城市</option>
  <option value="beijing">北京</option>
  <option value="shanghai">上海</option>
  <option value="guangzhou">广州</option>
</select>

<p>选择的城市:{{ selectedCity }}</p>
使用 ng-options(推荐)
<select ng-model="selectedCity" ng-options="city.code as city.name for city in cities">
  <option value="">-- 请选择 --</option>
</select>

<p>代码:{{ selectedCity }}</p>
<p>名称:{{ getCityName(selectedCity) }}</p>
$scope.cities = [
  { code: 'bj', name: '北京' },
  { code: 'sh', name: '上海' },
  { code: 'gz', name: '广州' }
];

$scope.getCityName = function(code) {
  var city = $scope.cities.find(function(c) {
    return c.code === code;
  });
  return city ? city.name : '';
};
ng-options 语法详解
<!-- 1. 数组:值作为显示文本 -->
<select ng-model="selected" ng-options="item for item in items"></select>

<!-- 2. 数组:值和显示文本不同 -->
<select ng-model="selected" ng-options="item.id as item.name for item in items"></select>

<!-- 3. 数组:分组 -->
<select ng-model="selected" ng-options="item.name group by item.category for item in items"></select>

<!-- 4. 对象:键值对 -->
<select ng-model="selected" ng-options="key as value for (key, value) in object"></select>

<!-- 5. 对象:键值对(值作为显示文本) -->
<select ng-model="selected" ng-options="key for (key, value) in object"></select>

四、ng-model 的修饰符

1. ng-model-options

控制数据绑定的行为。

<!-- 延迟更新(失去焦点时才更新) -->
<input type="text" ng-model="name" ng-model-options="{ updateOn: 'blur' }">

<!-- 防抖(延迟 500ms 更新) -->
<input type="text" ng-model="name" ng-model-options="{ debounce: 500 }">

<!-- 多事件触发 -->
<input type="text" ng-model="name" ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }">

<!-- 允许无效值 -->
<input type="email" ng-model="email" ng-model-options="{ allowInvalid: true }">

2. ng-trim

自动去除输入值的首尾空格(默认为 true)。

<!-- 自动去除空格 -->
<input type="text" ng-model="name" ng-trim="true">

<!-- 保留空格 -->
<input type="text" ng-model="name" ng-trim="false">

五、表单验证与 ng-model

ng-model 与表单验证紧密相关,通过 $error$valid/$invalid 等属性进行验证。

1. 基本验证

<form name="myForm" novalidate>
  <input type="text" 
         name="username" 
         ng-model="username"
         required
         ng-minlength="3"
         ng-maxlength="10"
         ng-pattern="/^[a-zA-Z]+$/">
  
  <p ng-show="myForm.username.$error.required">用户名必填</p>
  <p ng-show="myForm.username.$error.minlength">至少3个字符</p>
  <p ng-show="myForm.username.$error.maxlength">最多10个字符</p>
  <p ng-show="myForm.username.$error.pattern">只能包含字母</p>
  
  <p>有效:{{ myForm.username.$valid }}</p>
  <p>无效:{{ myForm.username.$invalid }}</p>
  <p>脏:{{ myForm.username.$dirty }}</p>
  <p>原始:{{ myForm.username.$pristine }}</p>
</form>

2. 表单状态属性

属性 说明
$valid 表单/字段是否有效
$invalid 表单/字段是否无效
$pristine 表单/字段是否未被修改
$dirty 表单/字段是否已被修改
$touched 表单/字段是否已被触碰
$untouched 表单/字段是否未被触碰
$error 包含所有验证错误的对象

3. 实时验证示例

<form name="myForm" novalidate>
  <div class="form-group" ng-class="{ 'has-error': myForm.email.$invalid && myForm.email.$dirty }">
    <label>邮箱</label>
    <input type="email" 
           name="email" 
           ng-model="email"
           required>
    <p class="help-block" ng-show="myForm.email.$error.required && myForm.email.$dirty">邮箱必填</p>
    <p class="help-block" ng-show="myForm.email.$error.email && myForm.email.$dirty">邮箱格式不正确</p>
  </div>
  
  <button type="submit" ng-disabled="myForm.$invalid">提交</button>
</form>

六、高级用法

1. 自定义指令中使用 ng-model

angular.module('myApp').directive('myInput', function() {
  return {
    restrict: 'E',
    require: 'ngModel',
    template: '<input type="text" ng-model="ngModel">',
    scope: {
      ngModel: '='
    },
    link: function(scope, element, attrs, ngModelCtrl) {
      // 访问 ngModelController
      ngModelCtrl.$formatters.push(function(value) {
        // 格式化模型值到视图
        return value ? value.toUpperCase() : '';
      });
      
      ngModelCtrl.$parsers.push(function(value) {
        // 解析视图值到模型
        return value ? value.toLowerCase() : '';
      });
    }
  };
});

2. $formatters$parsers

// 在控制器中
$scope.$watch('price', function(newVal) {
  // 监听模型变化
});

// 在自定义指令中
link: function(scope, element, attrs, ngModelCtrl) {
  // 模型 → 视图(格式化)
  ngModelCtrl.$formatters.push(function(modelValue) {
    return modelValue ? modelValue.toFixed(2) : '';
  });
  
  // 视图 → 模型(解析)
  ngModelCtrl.$parsers.push(function(viewValue) {
    return parseFloat(viewValue);
  });
}

3. $validators$asyncValidators

// 同步验证
ngModelCtrl.$validators.custom = function(modelValue, viewValue) {
  return modelValue && modelValue.length >= 3;
};

// 异步验证
ngModelCtrl.$asyncValidators.unique = function(modelValue, viewValue) {
  return $http.get('/api/check-username', { username: modelValue })
    .then(function(response) {
      return response.data.available;
    });
};

七、常见问题与最佳实践

1. 避免在 ng-repeat 中直接使用原始类型

<!-- 不推荐 -->
<div ng-repeat="item in [1, 2, 3]">
  <input type="checkbox" ng-model="item">
</div>

<!-- 推荐 -->
<div ng-repeat="item in items">
  <input type="checkbox" ng-model="item.checked">
</div>

2. 使用 ng-model-options 优化性能

<!-- 搜索框:使用防抖减少更新频率 -->
<input type="text" 
       ng-model="searchText" 
       ng-model-options="{ debounce: 300 }"
       placeholder="搜索...">

3. 处理初始值

// 确保模型有初始值
$scope.user = {
  name: '',
  email: '',
  gender: 'male'  // 默认值
};

4. 避免在表达式中直接修改模型

<!-- 不推荐 -->
<input type="text" ng-model="name" ng-change="name = name.toUpperCase()">

<!-- 推荐 -->
<input type="text" ng-model="name" ng-change="formatName()">
$scope.formatName = function() {
  $scope.name = $scope.name.toUpperCase();
};

八、总结

ng-model 是 AngularJS 双向数据绑定的核心,通过它可以轻松实现表单控件与模型数据的同步。掌握 ng-model 的各种用法、修饰符和验证机制,是构建响应式表单应用的关键。

关键点

  • 双向绑定:视图 ↔ 模型自动同步
  • 支持多种表单控件:文本、复选框、单选框、下拉框
  • 配合表单验证:$valid, $invalid, $error
  • 修饰符:ng-model-options, ng-trim
  • 高级功能:$formatters, $parsers, $validators
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐