### 18.11. 预定义的 FormController
前面的“表单控制”那章,实际上讲的就是 _FormController_ ,只是那里是从 `scope` 中获取到的引用。现在从指令定义的角度,来更清楚地了解 _FormController_ 及 _NgModelController_ 是如何配合工作的。
先说一下, _form_ 和 _ngForm_ 是官方定义的两个指令,但是它们其实是同一个东西。前者只允许以标签形式使用,而后者允许 `EAC` 的形式。DOM 结构中, `form` 标签不能嵌套,但是 ng 的指令没有这个限制。不管是 _form_ 还是 _ngForm_ ,它们的 `controller` 都被命名成了 `form` 。 所以 _require_ 这个参数不要写错了。
_FormController_ 的几个成员是很好理解的:
_$pristine_ 表单是否被动过_$dirty_ 表单是否没被动过_$valid_ 表单是否检验通过_$invalid_ 表单是否检验未通过_$error_ 表单中的错误_$setDirty()_ 直接设置 _$dirty_ 及 _$pristine_
<div ng-controller="TestCtrl">
<div ng-form test>
<input ng-model="a" type="email" />
<button ng-click="do()">查看</button>
</div>
</div>
var app = angular.module('Demo', [], angular.noop);
app.directive('test', function(){
var link = function($scope, $element, $attrs, $ctrl){
$scope.do = function(){
//$ctrl.$setDirty();
console.log($ctrl.$pristine); //form是否没被动过
console.log($ctrl.$dirty); //form是否被动过
console.log($ctrl.$valid); //form是否被检验通过
console.log($ctrl.$invalid); //form是否有错误
console.log($ctrl.$error); //form中有错误的字段
}
}
return {compile: function(){return link},
require: 'form',
restrict: 'A'}
});
app.controller('TestCtrl', function($scope){
});
_$error_ 这个属性,是一个对象, `key` 是错误名, `value` 部分是一个列表,其成员是对应的 _NgModelController_ 的实例。
_FormController_ 可以自由增减它包含的那些,类似于 _NgModelController_ 的实例。在 DOM 结构上,有 `ng-model` 的 `input` 节点的 _NgMoelController_ 会被自动添加。
_$addControl()_ 添加一个 conroller _$removeControl()_ 删除一个 controller
这两个手动使用机会应该不会很多。被添加的实例也可以手动实现所有的 _NgModelController_ 的方法
<div ng-controller="TestCtrl">
<bb />
<div ng-form test>
<input ng-model="a" type="email" />
<button ng-click="add()">添加</button>
</div>
</div>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('test', function(){
4 var link = function($scope, $element, $attrs, $ctrl){
5 $scope.add = function(){
6 $ctrl.$addControl($scope.bb);
7 console.log($ctrl);
8 }
9 }
1011 return {compile: function(){return link},
12 require: 'form',
13 restrict: 'A'}
14 });
1516 app.directive('bb', function(){
17 var controller = function($scope, $element, $attrs, $transclude){
18 $scope.bb = this;
19 this.$name = 'bb';
20 }
2122 return {compile: angular.noop,
23 restrict: 'E',
24 controller: controller}
25 });
2627 app.controller('TestCtrl', function($scope){
28 });
整合 _FormController_ 和 _NgModelController_ 就很容易扩展各种类型的字段:
<div ng-controller="TestCtrl">
<form name="f">
<input type="my" ng-model="a" />
<button ng-click="show()">查看</button>
</form>
</div>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('input', function(){
4 var link = function($scope, $element, $attrs, $ctrl){
5 console.log($attrs.type);
6 var validator = function(v){
7 if(v == '123'){
8 $ctrl.$setValidity('my', true);
9 return v;
10 } else {
11 $ctrl.$setValidity('my', false);
12 return undefined;
13 }
14 }
1516 $ctrl.$formatters.push(validator);
17 $ctrl.$parsers.push(validator);
18 }
1920 return {compile: function(){return link},
21 require: 'ngModel',
22 restrict: 'E'}
23 });
2425 app.controller('TestCtrl', function($scope){
26 $scope.show = function(){
27 console.log($scope.f);
28 }
29 });
虽然官方原来定义了几种 `type` ,但这不妨碍我们继续扩展新的类型。如果新的 `type` 参数值不在官方的定义列表里,那会按 `text` 类型先做处理,这其实什么影响都没有。剩下的,就是写我们自己的验证逻辑就行了。
上面的代码是参见官方的做法,使用格式化的过程,同时在里面做有效性检查。
- Introduction
- 关于AngularJS
- 关于本文档
- 开始的例子
- 依赖注入
- 作用域
- 数据绑定与模板
- 数据->模板
- 模板->数据
- 数据->模板->数据->模板
- 模板
- 定义模板内容
- 内容渲染控制
- 节点控制
- 事件绑定
- 表单控件
- 模板中的过滤器
- 排序 orderBy
- 过滤列表 filter
- 其它
- 例子:表头排序
- 例子:搜索
- 锚点路由
- 路由定义
- 参数定义
- 业务处理
- 定义模板变量标识标签
- AJAX
- HTTP请求
- 广义回调管理
- 工具函数
- 上下文绑定
- 对象处理
- 类型判定
- 其它服务
- 日志
- 缓存
- 计时器
- 表达式函数化
- 模板单独使用
- 自定义模块和服务
- 模块和服务的概念与关系
- 定义模块
- 定义服务
- 引入模块并使用服务
- 附加模块 ngResource
- 使用引入与整体概念
- 基本定义
- 基本使用
- 定义和使用时的占位量
- 实例
- AngularJS与其它框架的混用(jQuery, Dojo)
- 自定义过滤器
- 自定义指令directive
- 指令的使用
- 指令的执行过程
- 基本的自定义方法
- 属性值类型的自定义
- Compile的细节
- transclude的细节
- 把节点内容作为变量处理的类型
- 指令定义时的参数
- Attributes的细节
- 预定义的 NgModelController
- 预定义的 FormController
- 示例:文本框
- 示例:模板控制语句 for
- 示例:模板控制语句 if/else