概述
Angular JS的form指令提供表单相关的功能,它有两种形式:form和ng-form。
form和ng-form几乎是一模一样的,只有很小的一点区别:
form | ng-form |
---|---|
只有E模式 | 有EAC三种模式 |
只会判断和监测name属性 | 会判断和监测name和ng-form属性,悠闲name属性 |
实现细节
必要的时候监听submit事件
如果没有设置action属性时,form指令会监听submit事件,然后添加默认的响应。
if (!('action' in attr)) {
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
formElement.on('$destroy', function() {
$timeout(function() {
formElement[0].removeEventListener('submit', handleFormSubmission);
}, 0, false);
});
}
代码中最关键的是调用$commitViewValue和$setSubmitted函数,这两个函数实现了更新数据和设置已提交标识。这里的controller实际上是form指令的controller。
$commitViewValue只是调用子controller的$commitViewValue,form controller的子controller只有子form和ng-model的controller,所以最终调用的是ng-model的controller里的¥commitViewValue,具体将在ng-model指令里分析。
$setSubmitted功能更加简单,为form元素添加ng-submitted的css类,然后设置submitted标记为true,最后调用父form controller的$setSubmitted方法。
和父form建立关系
在form指令link的pre里,会把自己的controller添加到父form的controller里去,实现父子form的关联关系,如果没有父form,就什么也不做。
添加的过程:
form.$addControl = function(control) {
// Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
// and not added to the scope. Now we throw an error.
assertNotHasOwnProperty(control.$name, 'input');
controls.push(control);
if (control.$name) {
form[control.$name] = control;
}
control.$$parentForm = form;
};
其中control.$name为name或者ng-form属性的值,计算过程为:
form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
从这个添加过程可以看出,在父controller中会记录一个子controller列表,如果子controller设置了name属性,父controller还会添加对应名称的属性值(可以实现数据绑定,具体实现过程为:监测name属性,调用rename方法)。
同时在子controller中也会记录下父的form。这个过程是后续form指令各种操作的基础,他保证了表单操作时上下级的关联关系。
form controller中定义的方法
在form controller中定义了一些列的form操作方法,可以分为三大类:
1、controller关系操作,包括:$addControl,$removeControl,$$renameControl
2、controller对数据的操作,这个部分一般都是向下递归调用,最终调用ng-model中对应的函数,包括:$commitViewValue,$rollbackViewValue
3、form状态操作,这部分的方法一般都是递归调用,设置状态和css类,包括:$setPristine,$setUntouched,$setSubmitted,$setDirty。
form指令中支持的css类
在form指令中随着数据状态的变化,会自动的添加对应的css类,从而支持对于不同状态下的样式控制,其支持的css类有:
css类名 | 说明 |
---|---|
ng-valid | 全部数据都是有效的 |
ng-invalid | 有无效的数据 |
ng-pending | 表单处理中的状态 |
ng-pristine | 数据是干净的,与dirty相对 |
ng-dirty | 数据被修改过 |
ng-submitted | 数据已经被提交过 |
代码样例
<!DOCTYPE html>
<html lang="en" ng-app="app">
<!--<html>-->
<head>
<title>Test</title>
</head>
<body>
<style>
.my-form {
transition:all linear 0.5s;
background: transparent;
}
.my-form.ng-invalid {
background: red;
}
</style>
<form name="myForm" ng-controller="ExampleController" class="my-form">
userType: <input name="input" ng-model="userType" required>
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
<code>userType = {{userType}}</code><br>
<code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
<code>myForm.input.$error = {{myForm.input.$error}}</code><br>
<code>myForm.$valid = {{myForm.$valid}}</code><br>
<code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
</form>
<script src="./node_modules/angular/angular.js" type="text/javascript"></script>
<script>
angular.module('app', [])
.controller('ExampleController', ['$scope', function ($scope) {
$scope.userType = 'guest';
}]);
</script>
</body>
</html>
这段代码实现了form指令的基本功能,会判断表单输入项的合法性。如果输入为空,背景就会为红色。