在前面文章中提到一旦聲明了require,則鏈接函數具有第四個參數:controller。
可見require和controller是配合使用的。
在自定義指令中使用controller,目的往往是要封裝一些行為,給其他指令使用。下面是一個簡單的例子:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <script src="../lib/angular-1.3.16/angular.min.js"></script> <title></title> <script language="JavaScript"> var app = angular.module('myapp',[]); app.directive('d1',function() { return { controller: function ($scope) { this.method1 = function () { return 'World'; }; } } }); app.directive('d2',function() { return { require: 'd1', link: function (scope, elem, attrs, d1) { scope.greeting = d1.method1(); } } }); </script> </head> <body ng-app="myapp"> <div d1 d2>Hello {{greeting}}!</div> </body> </html>
輸出:
Hello World!
從這個例子可以看到,在DOM中需要聲明d1、d2,如果不聲明d1,那么d2在檢查require里的'd1'時,就會拋出異常。
AngularJs為我們提供了一些標記,使用它們可以告訴AngularJs怎么查找所require的控制器:
1,沒標記。在當前元素中查找,如果找不到就拋出錯誤。
2,?標記。在當前元素中查找,如果查找不到,不拋出錯誤,鏈接函數的第四個參數為null(如上面代碼link: function (scope, elem, attrs, d1)中的d1)
3,^標記。不僅在當前元素中查找,還查找其所有父級。如果找不到就拋出錯誤。
4,^^標記。只在當前元素的父級中查找。如果找不到就拋出錯誤。
5,?^標記。不僅在當前元素中查找,還查找其所有父級。如果查找不到,不拋出錯誤,鏈接函數的第四個參數為null
6,?^^標記。只在當前元素的父級中查找。如果查找不到,不拋出錯誤,鏈接函數的第四個參數為null
我們修改一下上面例子的代碼,試驗一下第4條:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <script src="../lib/angular-1.3.16/angular.min.js"></script> <title></title> <script language="JavaScript"> var app = angular.module('myapp',[]); app.directive('d1',function() { return { controller: function ($scope) { this.method1 = function () { return 'World'; }; } } }); app.directive('d2',function() { return { require: '^^d1', link: function (scope, elem, attrs, d1) { scope.greeting = d1.method1(); } } }); </script> </head> <body ng-app="myapp"> <div d1 d2>Hello {{greeting}}!</div> </body> </html>
在Chrome瀏覽器的控制台可以看到錯誤提示:
Error: [$compile:ctreq] http://errors.angularjs.org/1.3.16/$compile/ctreq?p0=d1&p1=d2
點擊鏈接去看看(需要翻牆):
Error: $compile:ctreq
Controller 'd1', required by directive 'd2', can't be found!
果然找不到!因為d1放在d2所在的div中(當前元素),^^標記要求去父級找,當然沒有了。
在實際應用時,我們往往會require 'ngModel',也就是希望利用AngularJs內置指令ngModel里的方法,而不是自己重新寫:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <script src="../lib/angular-1.3.16/angular.min.js"></script> <title></title> <script language="JavaScript"> var app = angular.module('myApp',[]); app.directive('myDirective',function() { return { require: 'ngModel', link: function (scope, elem, attrs, model) { model.$parsers.unshift(function(value) { if (parseFloat(value)<1) { model.$setValidity('test', true); return parseFloat(value).toFixed(2); } else { model.$setValidity('test', false); return undefined; } }); } } }); </script> </head> <body ng-app="myApp"> <form name="form1"> <div> 請輸入小於1的一個小數:<input name="input1" type="number" ng-model="aNumber" my-directive /> 保留小數點后2位:{{aNumber}} </div> <span ng-show="form1.input1.$error.test">這個數並不小於1!</span> </form> </body> </html>
上面例子就是利用了ngModel里已有的$parser屬性和$setValidity方法。
$parsers里保存了一組function, 每當DOM里數據變化的時候, 這組function會被調用。