AngularJS 表单学习笔记(详细版)


一、AngularJS 表单核心概念

AngularJS 对 HTML 表单进行了深度扩展,提供了双向数据绑定、表单验证、状态追踪等能力。表单在 AngularJS 中是一等公民。

1.1 核心特性

特性 说明
双向数据绑定 ng-model 将表单控件与模型自动同步
表单状态追踪 自动追踪 pristine/dirty/valid/invalid 等状态
内置验证 required、minlength、maxlength、pattern 等
自定义验证 通过指令实现复杂验证逻辑
CSS 类自动添加 根据状态自动添加 CSS 类,方便样式控制

二、基础用法:ng-model

ng-model 是 AngularJS 表单的核心指令,实现视图 ↔ 模型的双向绑定。

2.1 基本绑定

<form ng-app="myApp" ng-controller="FormController">
    <input type="text" ng-model="user.name" placeholder="姓名">
    <input type="email" ng-model="user.email" placeholder="邮箱">
    <p>你好,{{ user.name }}!邮箱:{{ user.email }}</p>
</form>
angular.module('myApp', [])
    .controller('FormController', ['$scope', function($scope) {
        $scope.user = {
            name: '',
            email: ''
        };
    }]);

2.2 ng-model 支持的表单元素

元素 示例
<input type="text"> ng-model="user.name"
<input type="email"> ng-model="user.email"
<input type="number"> ng-model="user.age"
<input type="checkbox"> ng-model="user.agree"
<input type="radio"> ng-model="user.gender"
<select> ng-model="user.city"
<textarea> ng-model="user.bio"

2.3 各类型详细示例

<!-- 文本输入 -->
<input type="text" ng-model="user.name">

<!-- 邮箱 -->
<input type="email" ng-model="user.email">

<!-- 数字 -->
<input type="number" ng-model="user.age" min="0" max="150">

<!-- 复选框 -->
<input type="checkbox" ng-model="user.agree"> 同意条款

<!-- 单选按钮 -->
<input type="radio" ng-model="user.gender" value="male"><input type="radio" ng-model="user.gender" value="female"><!-- 下拉选择 -->
<select ng-model="user.city">
    <option value="">请选择城市</option>
    <option value="beijing">北京</option>
    <option value="shanghai">上海</option>
    <option value="guangzhou">广州</option>
</select>

<!-- 多行文本 -->
<textarea ng-model="user.bio" rows="4"></textarea>

三、表单与控件命名规则

AngularJS 会根据 name 属性将表单和控件注册到 $scope 上:

<form name="myForm" ng-app="myApp" ng-controller="FormController">
    <input name="userName" type="text" ng-model="user.name" required>
    <!-- myForm.userName 可访问该输入框的状态 -->
</form>

关键规则:

  • 表单的 name 属性 → 注册为 $scope.myForm
  • 控件的 name 属性 → 注册为 $scope.myForm.userName
  • 没有 name 属性的控件不会被追踪

四、表单状态追踪

4.1 表单级别状态

属性 类型 说明
myForm.$pristine boolean 表单是否未被修改过(原始状态)
myForm.$dirty boolean 表单是否已被修改过
myForm.$valid boolean 表单是否全部验证通过
myForm.$invalid boolean 表单是否存在验证失败
myForm.$submitted boolean 表单是否已提交
myForm.$error object 验证错误详情(按验证类型分组)

4.2 控件级别状态

属性 类型 说明
myForm.userName.$pristine boolean 该控件是否未被修改
myForm.userName.$dirty boolean 该控件是否已被修改
myForm.userName.$valid boolean 该控件验证是否通过
myForm.userName.$invalid boolean 该控件验证是否失败
myForm.userName.$touched boolean 该控件是否失去过焦点
myForm.userName.$untouched boolean 该控件是否从未失去焦点
myForm.userName.$error object 该控件的验证错误详情

4.3 状态流转图

                    修改内容
  $pristine ──────────────► $dirty
  (原始)                    (已修改)
      │                        │
      │  失去焦点              │  失去焦点
      ▼                        ▼
  $untouched ────────────► $touched
  (未触碰)                   (已触碰)

  $valid ◄──── 验证通过/失败 ────► $invalid

4.4 状态展示示例

<form name="userForm" ng-controller="FormController">
    <input name="name" type="text" ng-model="user.name" required>

    <div>
        <p>表单状态:</p>
        <ul>
            <li>$pristine:  {{ userForm.$pristine }}</li>
            <li>$dirty:     {{ userForm.$dirty }}</li>
            <li>$valid:     {{ userForm.$valid }}</li>
            <li>$invalid:   {{ userForm.$invalid }}</li>
            <li>$submitted: {{ userForm.$submitted }}</li>
        </ul>
    </div>

    <div>
        <p>name 控件状态:</p>
        <ul>
            <li>$pristine:  {{ userForm.name.$pristine }}</li>
            <li>$dirty:     {{ userForm.name.$dirty }}</li>
            <li>$valid:     {{ userForm.name.$valid }}</li>
            <li>$invalid:   {{ userForm.name.$invalid }}</li>
            <li>$touched:   {{ userForm.name.$touched }}</li>
            <li>$error:     {{ userForm.name.$error | json }}</li>
        </ul>
    </div>
</form>

五、自动 CSS 类

AngularJS 根据控件状态自动添加/移除 CSS 类,无需手动操作 DOM:

CSS 类 添加时机
ng-pristine 控件未被修改
ng-dirty 控件已被修改
ng-valid 验证通过
ng-invalid 验证失败
ng-touched 控件失去过焦点
ng-untouched 控件未失去过焦点
ng-valid-[key] 特定验证通过(如 ng-valid-required
ng-invalid-[key] 特定验证失败(如 ng-invalid-required

5.1 利用 CSS 类美化表单

/* 原始状态 —— 灰色边框 */
input.ng-pristine {
    border: 2px solid #ccc;
}

/* 修改过且有效 —— 绿色边框 */
input.ng-dirty.ng-valid {
    border: 2px solid #4caf50;
}

/* 修改过且无效 —— 红色边框 */
input.ng-dirty.ng-invalid {
    border: 2px solid #f44336;
}

/* 未修改时不要显示错误样式 */
input.ng-pristine.ng-invalid {
    border: 2px solid #ccc;
}

六、内置验证指令

6.1 验证指令一览

指令/属性 适用类型 说明
required 所有 必填
ng-required 所有 动态必填(表达式)
minlength text/number 最小长度
ng-minlength text/number 动态最小长度
maxlength text/number 最大长度
ng-maxlength text/number 动态最大长度
min number/date 最小值
max number/date 最大值
pattern text 正则匹配
ng-pattern text 动态正则匹配
type="email" input 邮箱格式验证
type="url" input URL 格式验证
type="number" input 数字验证

6.2 完整验证示例

<form name="regForm" ng-controller="RegController" novalidate>
    <!-- novalidate 禁用浏览器原生验证,使用 AngularJS 验证 -->

    <!-- 用户名:必填 + 长度限制 -->
    <div>
        <label>用户名</label>
        <input type="text"
               name="username"
               ng-model="user.username"
               required
               ng-minlength="3"
               ng-maxlength="20">
        <span ng-show="regForm.username.$dirty && regForm.username.$error.required">
            用户名必填
        </span>
        <span ng-show="regForm.username.$dirty && regForm.username.$error.minlength">
            用户名至少3个字符
        </span>
        <span ng-show="regForm.username.$dirty && regForm.username.$error.maxlength">
            用户名最多20个字符
        </span>
    </div>

    <!-- 邮箱:必填 + 邮箱格式 -->
    <div>
        <label>邮箱</label>
        <input type="email"
               name="email"
               ng-model="user.email"
               required>
        <span ng-show="regForm.email.$dirty && regForm.email.$error.required">
            邮箱必填
        </span>
        <span ng-show="regForm.email.$dirty && regForm.email.$error.email">
            邮箱格式不正确
        </span>
    </div>

    <!-- 年龄:必填 + 范围 -->
    <div>
        <label>年龄</label>
        <input type="number"
               name="age"
               ng-model="user.age"
               required
               min="1"
               max="150">
        <span ng-show="regForm.age.$dirty && regForm.age.$error.required">
            年龄必填
        </span>
        <span ng-show="regForm.age.$dirty && regForm.age.$error.min">
            年龄不能小于1
        </span>
        <span ng-show="regForm.age.$dirty && regForm.age.$error.max">
            年龄不能大于150
        </span>
    </div>

    <!-- 密码:必填 + 正则 -->
    <div>
        <label>密码</label>
        <input type="password"
               name="password"
               ng-model="user.password"
               required
               ng-pattern="/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/">
        <span ng-show="regForm.password.$dirty && regForm.password.$error.required">
            密码必填
        </span>
        <span ng-show="regForm.password.$dirty && regForm.password.$error.pattern">
            密码至少8位,需包含字母和数字
        </span>
    </div>

    <!-- 提交按钮 -->
    <button type="submit"
            ng-disabled="regForm.$invalid"
            ng-click="submit()">
        注册
    </button>
</form>
angular.module('myApp', [])
    .controller('RegController', ['$scope', function($scope) {
        $scope.user = {};

        $scope.submit = function() {
            if ($scope.regForm.$valid) {
                console.log('提交数据:', $scope.user);
                // 发送到后端...
            }
        };
    }]);

七、$error 对象详解

$error 是一个按验证类型分组的对象,是表单验证的核心查询接口。

7.1 控件级别 $error

// regForm.username.$error 的结构
{
    required: true,     // 未填写
    minlength: true,    // 长度不足
    maxlength: false,   // 长度未超限
    pattern: false      // 正则匹配通过
}

7.2 表单级别 $error

// regForm.$error 的结构 —— 按验证类型分组,值为控件数组
{
    required: [regForm.username, regForm.email],
    email: [regForm.email],
    minlength: [regForm.username]
}

7.3 利用 $error 做全局错误提示

<div ng-show="regForm.$submitted && regForm.$invalid">
    <p>表单存在以下错误:</p>
    <ul>
        <li ng-repeat="(key, value) in regForm.$error">
            {{ key }}: {{ value.length }} 个字段未通过
        </li>
    </ul>
</div>

八、ngMessages 模块(推荐)

ngMessages 是 AngularJS 1.3+ 引入的模块,用于优雅地管理验证消息,替代繁琐的 ng-show 判断。

8.1 引入 ngMessages

<script src="angular.js"></script>
<script src="angular-messages.js"></script>
angular.module('myApp', ['ngMessages']);

8.2 基本用法

<form name="myForm" ng-controller="MyController" novalidate>
    <div>
        <label>邮箱</label>
        <input type="email"
               name="email"
               ng-model="user.email"
               required>

        <!-- 使用 ng-messages -->
        <div ng-messages="myForm.email.$error" ng-if="myForm.email.$dirty">
            <div ng-message="required">邮箱必填</div>
            <div ng-message="email">邮箱格式不正确</div>
        </div>
    </div>
</form>

优势:

  • 代码更简洁,无需大量 ng-show
  • 默认只显示第一条错误消息(避免信息过载)
  • 可通过 ng-messages-multiple 显示所有错误

8.3 显示多条错误

<div ng-messages="myForm.email.$error"
     ng-if="myForm.email.$dirty"
     ng-messages-multiple>
    <div ng-message="required">邮箱必填</div>
    <div ng-message="email">邮箱格式不正确</div>
</div>

8.4 复用错误消息模板

<!-- 定义模板 -->
<script type="text/ng-template" id="error-messages">
    <div ng-message="required">此字段必填</div>
    <div ng-message="minlength">输入太短</div>
    <div ng-message="maxlength">输入太长</div>
    <div ng-message="email">邮箱格式不正确</div>
    <div ng-message="pattern">格式不符合要求</div>
    <div ng-message="min">值太小</div>
    <div ng-message="max">值太大</div>
</script>

<!-- 使用模板 -->
<div ng-messages="myForm.username.$error"
     ng-if="myForm.username.$dirty"
     ng-messages-include="error-messages">
</div>

<!-- 也可以在引用模板后追加自定义消息 -->
<div ng-messages="myForm.password.$error"
     ng-if="myForm.password.$dirty"
     ng-messages-include="error-messages">
    <div ng-message="pattern">密码需包含字母和数字,至少8位</div>
</div>

九、表单提交处理

9.1 方式一:ng-submit

<form name="myForm" ng-submit="onSubmit()" novalidate>
    <input name="name" ng-model="user.name" required>
    <button type="submit">提交</button>
</form>
$scope.onSubmit = function() {
    if ($scope.myForm.$valid) {
        // 提交逻辑
        console.log($scope.user);
    }
};

9.2 方式二:ng-click

<form name="myForm" novalidate>
    <input name="name" ng-model="user.name" required>
    <button type="button" ng-click="onSubmit()" ng-disabled="myForm.$invalid">
        提交
    </button>
</form>

9.3 方式三:阻止默认提交 + 手动验证

<form name="myForm" ng-submit="onSubmit($event)" novalidate>
    <input name="name" ng-model="user.name" required>
    <button type="submit">提交</button>
</form>
$scope.onSubmit = function(event) {
    event.preventDefault();

    // 标记所有控件为 dirty,触发错误显示
    angular.forEach($scope.myForm.$error, function(controls, validationType) {
        angular.forEach(controls, function(control) {
            control.$setDirty();
        });
    });

    if ($scope.myForm.$valid) {
        // 提交
    }
};

十、自定义验证

10.1 使用指令添加自定义验证

// 验证用户名是否已存在(异步验证)
angular.module('myApp')
    .directive('usernameExists', ['$q', 'UserService', function($q, UserService) {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, ngModelCtrl) {

                // 同步验证器
                ngModelCtrl.$validators.invalidChars = function(modelValue, viewValue) {
                    var value = modelValue || viewValue;
                    // 不允许包含特殊字符
                    return /^[a-zA-Z0-9_]+$/.test(value);
                };

                // 异步验证器
                ngModelCtrl.$asyncValidators.usernameExists = function(modelValue, viewValue) {
                    var value = modelValue || viewValue;
                    if (!value) return $q.resolve();

                    return UserService.checkUsername(value).then(function(exists) {
                        if (exists) {
                            return $q.reject('用户名已存在');
                        }
                        return true;
                    });
                };
            }
        };
    }]);
<input type="text"
       name="username"
       ng-model="user.username"
       required
       username-exists>

<div ng-messages="myForm.username.$error"
     ng-if="myForm.username.$dirty">
    <div ng-message="required">用户名必填</div>
    <div ng-message="invalidChars">用户名只能包含字母、数字和下划线</div>
    <div ng-message="usernameExists">用户名已存在</div>
</div>

10.2 密码确认验证

angular.module('myApp')
    .directive('passwordMatch', [function() {
        return {
            require: 'ngModel',
            scope: {
                passwordMatch: '='
            },
            link: function(scope, element, attrs, ngModelCtrl) {
                ngModelCtrl.$validators.passwordMatch = function(modelValue) {
                    return modelValue === scope.passwordMatch;
                };

                scope.$watch('passwordMatch', function() {
                    ngModelCtrl.$validate();
                });
            }
        };
    }]);
<input type="password" name="password" ng-model="user.password" required>
<input type="password"
       name="confirmPassword"
       ng-model="user.confirmPassword"
       required
       password-match="user.password">

<div ng-messages="myForm.confirmPassword.$error"
     ng-if="myForm.confirmPassword.$dirty">
    <div ng-message="required">请确认密码</div>
    <div ng-message="passwordMatch">两次密码不一致</div>
</div>

十一、动态表单

11.1 ng-repeat 生成表单

<form name="surveyForm" ng-controller="SurveyController">
    <div ng-repeat="question in questions">
        <label>{{ question.text }}</label>

        <!-- 单选题 -->
        <div ng-if="question.type === 'radio'">
            <label ng-repeat="option in question.options">
                <input type="radio"
                       name="q{{ $parent.$index }}"
                       ng-model="question.answer"
                       ng-value="option.value">
                {{ option.label }}
            </label>
        </div>

        <!-- 多选题 -->
        <div ng-if="question.type === 'checkbox'">
            <label ng-repeat="option in question.options">
                <input type="checkbox"
                       ng-model="question.answers[option.value]">
                {{ option.label }}
            </label>
        </div>

        <!-- 文本题 -->
        <div ng-if="question.type === 'text'">
            <input type="text" ng-model="question.answer">
        </div>
    </div>

    <button ng-click="submit()" ng-disabled="surveyForm.$invalid">提交</button>
</form>

11.2 动态 ng-required

<!-- 根据条件决定是否必填 -->
<input type="text"
       name="companyName"
       ng-model="user.companyName"
       ng-required="user.type === 'enterprise'">

<!-- 如果用户类型是企业,则公司名称必填 -->
<select ng-model="user.type">
    <option value="personal">个人</option>
    <option value="enterprise">企业</option>
</select>

十二、表单重置

$scope.resetForm = function() {
    // 1. 重置模型数据
    $scope.user = {
        name: '',
        email: '',
        age: null
    };

    // 2. 重置表单状态
    $scope.myForm.$setPristine();   // 恢复为原始状态
    $scope.myForm.$setUntouched();  // 恢复为未触碰状态
};
<button type="button" ng-click="resetForm()">重置</button>

十三、$setValidity 手动设置验证状态

// 在指令或控制器中手动设置验证状态
ngModelCtrl.$setValidity('customError', false);  // 标记为无效
ngModelCtrl.$setValidity('customError', true);   // 标记为有效

// 在控制器中通过表单访问
$scope.myForm.username.$setValidity('taken', false);
<div ng-message="taken">该用户名已被占用</div>

十四、完整实战示例:注册表单

<!DOCTYPE html>
<html ng-app="regApp">
<head>
    <meta charset="UTF-8">
    <title>注册表单</title>
    <script src="angular.js"></script>
    <script src="angular-messages.js"></script>
    <style>
        .form-group { margin-bottom: 15px; }
        .form-group label { display: block; margin-bottom: 5px; font-weight: bold; }

        input.ng-dirty.ng-valid { border: 2px solid #4caf50; }
        input.ng-dirty.ng-invalid { border: 2px solid #f44336; }
        input.ng-pristine { border: 2px solid #ccc; }

        .error-messages { color: #f44336; font-size: 0.85em; margin-top: 4px; }
        .error-messages div { margin-top: 2px; }

        button:disabled { opacity: 0.5; cursor: not-allowed; }
    </style>
</head>
<body ng-controller="RegController">
    <h2>用户注册</h2>

    <form name="regForm" ng-submit="register()" novalidate>

        <div class="form-group">
            <label>用户名</label>
            <input type="text"
                   name="username"
                   ng-model="user.username"
                   required
                   ng-minlength="3"
                   ng-maxlength="20"
                   ng-pattern="/^[a-zA-Z0-9_]+$/"
                   placeholder="3-20位字母、数字或下划线">
            <div class="error-messages"
                 ng-messages="regForm.username.$error"
                 ng-if="regForm.username.$dirty">
                <div ng-message="required">用户名必填</div>
                <div ng-message="minlength">用户名至少3个字符</div>
                <div ng-message="maxlength">用户名最多20个字符</div>
                <div ng-message="pattern">只能包含字母、数字和下划线</div>
            </div>
        </div>

        <div class="form-group">
            <label>邮箱</label>
            <input type="email"
                   name="email"
                   ng-model="user.email"
                   required
                   placeholder="example@domain.com">
            <div class="error-messages"
                 ng-messages="regForm.email.$error"
                 ng-if="regForm.email.$dirty">
                <div ng-message="required">邮箱必填</div>
                <div ng-message="email">邮箱格式不正确</div>
            </div>
        </div>

        <div class="form-group">
            <label>密码</label>
            <input type="password"
                   name="password"
                   ng-model="user.password"
                   required
                   ng-minlength="8"
                   ng-pattern="/^(?=.*[A-Za-z])(?=.*\d)/"
                   placeholder="至少8位,包含字母和数字">
            <div class="error-messages"
                 ng-messages="regForm.password.$error"
                 ng-if="regForm.password.$dirty">
                <div ng-message="required">密码必填</div>
                <div ng-message="minlength">密码至少8个字符</div>
                <div ng-message="pattern">密码需包含字母和数字</div>
            </div>
        </div>

        <div class="form-group">
            <label>确认密码</label>
            <input type="password"
                   name="confirmPwd"
                   ng-model="user.confirmPwd"
                   required
                   password-match="user.password"
                   placeholder="再次输入密码">
            <div class="error-messages"
                 ng-messages="regForm.confirmPwd.$error"
                 ng-if="regForm.confirmPwd.$dirty">
                <div ng-message="required">请确认密码</div>
                <div ng-message="passwordMatch">两次密码不一致</div>
            </div>
        </div>

        <div class="form-group">
            <label>年龄</label>
            <input type="number"
                   name="age"
                   ng-model="user.age"
                   required
                   min="1"
                   max="150"
                   placeholder="1-150">
            <div class="error-messages"
                 ng-messages="regForm.age.$error"
                 ng-if="regForm.age.$dirty">
                <div ng-message="required">年龄必填</div>
                <div ng-message="min">年龄不能小于1</div>
                <div ng-message="max">年龄不能大于150</div>
                <div ng-message="number">请输入有效数字</div>
            </div>
        </div>

        <div class="form-group">
            <label>
                <input type="checkbox" ng-model="user.agree" required>
                我已阅读并同意服务条款
            </label>
        </div>

        <button type="submit" ng-disabled="regForm.$invalid">
            注册
        </button>
        <button type="button" ng-click="reset()">重置</button>
    </form>

    <pre ng-show="submitted">{{ user | json }}</pre>
</body>
</html>
angular.module('regApp', ['ngMessages'])
    .directive('passwordMatch', [function() {
        return {
            require: 'ngModel',
            scope: { passwordMatch: '=' },
            link: function(scope, element, attrs, ngModelCtrl) {
                ngModelCtrl.$validators.passwordMatch = function(modelValue) {
                    return modelValue === scope.passwordMatch;
                };
                scope.$watch('passwordMatch', function() {
                    ngModelCtrl.$validate();
                });
            }
        };
    }])
    .controller('RegController', ['$scope', '$http', function($scope, $http) {
        $scope.user = {};
        $scope.submitted = false;

        $scope.register = function() {
            if ($scope.regForm.$valid) {
                $http.post('/api/register', $scope.user)
                    .then(function(response) {
                        $scope.submitted = true;
                        alert('注册成功!');
                    }, function(error) {
                        alert('注册失败:' + error.data.message);
                    });
            }
        };

        $scope.reset = function() {
            $scope.user = {};
            $scope.submitted = false;
            $scope.regForm.$setPristine();
            $scope.regForm.$setUntouched();
        };
    }]);

十五、常见问题与注意事项

15.1 novalidate

<!-- 始终添加 novalidate,禁用浏览器原生验证 -->
<form name="myForm" novalidate>

不添加 novalidate 会导致浏览器原生验证和 AngularJS 验证同时生效,产生冲突。

15.2 type=“number” 的坑

<!-- type="number" 时,非数字输入不会更新 ng-model -->
<input type="number" ng-model="user.age">

<!-- 如果需要允许任意输入并自行验证,用 type="text" + ng-pattern -->
<input type="text" ng-model="user.age" ng-pattern="/^\d+$/">

15.3 checkbox 的 required 验证

<!-- checkbox 的 required 验证:必须勾选 -->
<input type="checkbox" ng-model="user.agree" name="agree" required>
<span ng-show="myForm.agree.$dirty && myForm.agree.$error.required">
    必须同意条款
</span>

15.4 select 的默认空值

<!-- select 的第一个 option 为空值时,ng-model 不会自动选中 -->
<select ng-model="user.city" required>
    <option value="">请选择</option>
    <option value="bj">北京</option>
    <option value="sh">上海</option>
</select>

<!-- 使用 ng-options 更推荐 -->
<select ng-model="user.city"
        ng-options="city.code as city.name for city in cities"
        required>
    <option value="">请选择</option>
</select>

15.5 表单嵌套

<!-- AngularJS 不支持 form 嵌套,用 ng-form 替代内层 -->
<form name="outerForm" ng-submit="submit()">
    <div ng-form="addressForm">
        <input name="city" ng-model="address.city" required>
        <span ng-show="addressForm.city.$error.required">城市必填</span>
    </div>

    <div ng-form="contactForm">
        <input name="phone" ng-model="contact.phone" required>
        <span ng-show="contactForm.phone.$error.required">电话必填</span>
    </div>

    <button type="submit" ng-disabled="outerForm.$invalid">提交</button>
</form>

ng-formform 功能相同,但不会创建新的 HTML <form> 元素,支持嵌套,且子表单的验证状态会冒泡到父表单。


十六、总结思维导图

AngularJS Form
├── 核心指令
│   ├── ng-model ────── 双向绑定
│   ├── ng-submit ───── 表单提交
│   ├── ng-form ─────── 嵌套表单
│   └── novalidate ──── 禁用原生验证
├── 状态追踪
│   ├── $pristine / $dirty ── 是否修改
│   ├── $valid / $invalid ── 验证结果
│   ├── $touched / $untouched ── 焦点状态
│   ├── $submitted ── 是否提交
│   └── $error ── 错误详情
├── 自动 CSS 类
│   ├── ng-pristine / ng-dirty
│   ├── ng-valid / ng-invalid
│   ├── ng-touched / ng-untouched
│   └── ng-valid-xxx / ng-invalid-xxx
├── 内置验证
│   ├── required / ng-required
│   ├── minlength / maxlength
│   ├── min / max
│   ├── pattern / ng-pattern
│   └── type="email" / "url" / "number"
├── ngMessages
│   ├── ng-messages ── 消息容器
│   ├── ng-message ── 单条消息
│   ├── ng-messages-multiple ── 显示多条
│   └── ng-messages-include ── 复用模板
├── 自定义验证
│   ├── $validators ── 同步验证
│   ├── $asyncValidators ── 异步验证
│   ├── $setValidity() ── 手动设置
│   └── 自定义指令
├── 表单操作
│   ├── $setPristine() ── 重置为原始
│   ├── $setUntouched() ── 重置为未触碰
│   └── $rollbackViewValue() ── 回滚
└── 注意事项
    ├── 必须加 novalidate
    ├── type="number" 的坑
    ├── ng-form 替代嵌套 form
    └── select 默认空值问题

以上内容覆盖了 AngularJS 表单的双向绑定、状态追踪、内置验证、ngMessages、自定义验证、动态表单、表单重置等核心知识点,可作为系统学习和日常开发的完整参考。

Logo

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

更多推荐