### 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