angular指令高级

scope 作用域

1
<h1 click-me>{{name}}</h1>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
var app = angular.module('myapp',[]);
app.controller('firstCtrl',['$scope', function($scope){
$scope.name = 'xwill';
}]);
app.directive('clickMe', [function(){
return {
restrict: 'A',
scope: {}, //清空controller中scope值,默认是继承的
link: function(scope, elem, attr){
elem.bind('click', function(){
console.log(scope.name); //undefined,scope值被清空
});
}
}
}]);
</script>

使用 scope: {} 即给指令创建自己的作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.directive('clickMe',[function(){
return {
restrict: 'A',
controller: 'secondCtrl',
link: function(scope,elem,attr){
elem.bind('click',function(){
console.log(scope.name);
});
}
}
}]);
app.controller('secondCtrl',['$scope',function($scope){
$scope.name = 'xwill2'; //将会覆盖 firstCtrl 中 scope 的值
}]);

使用 controller 属性可改变 scope 指向

scope 通讯,directive 中的 model 改变,controller 中的 model 跟着变

1
2
3
4
<div ng-controller="TestCtrl">
{{name}}
<hello ng-model="name"></hello>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
app.controller('TestCtrl', ['$scope', function($scope) {
$scope.name = 'test';
}]);
app.directive('hello', ['$timeout', function ($timeout) {
return {
restrict: 'EA',
scope: {
myName: '=ngModel'
},
link: function (scope, iElement, iAttrs) {
setTimeout(function(){
scope.$apply(function(){
scope.myName = 'it changes';
});
},1000);
}
};
}]);

&、=、@ 的区别

1
2
3
4
<div ng-controller="TestCtrl">
<div free person="calo" crime="gambel" shout="say('no!')"></div>
<div free person="corleone" crime="killing" shout="say('nonono!')"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script type="text/javascript">
app.controller('TestCtrl', ['$scope', function($scope) {
$scope.calo = {name: 'calo', age: 22};
$scope.corleone = {name: 'corleone', age: 34};

$scope.say = function(word){
alert(word);
}
}])
app.directive('free', [function() {
return {
restrict: 'A',
template: '<div>hello {{myPerson.name}},{{myPerson.age}},your crime is {{myCrime}}</div>',
scope: {
myPerson: '=person', //=绑定 controller 中 scope 的值
myCrime: '@crime', //@取字符串
shout: '&' //绑定方法
},
link: function(scope, iElement, iAttrs) {
iElement.bind('click',function(){
scope.shout();
});
}
};
}]);
</script>

= 用于绑定 controller 中的变量,
@ 获取属性的字面量值
& 绑定 function

require 属性

简单的理解,require 用于请求另外的 controller,传入当前 directive 的 linking function 中
简单例子:
html

1
2
3
4
5
<div ng-controller="TestCtrl">
<div add ng-model="num"></div>
<p>{{num}}</p>
<button ng-click="get()">get</button>
</div>

controller

1
2
3
4
5
6
app.controller('TestCtrl', ['$scope', function($scope) {
$scope.num = 1;
$scope.get = function() {
alert($scope.num);
}
}])

directive

1
2
3
4
5
6
7
8
9
10
11
12
app.directive('add', [function() {
return {
restrict: 'A',
require: 'ngModel',
template: '<button>add</button>',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
iElement.bind('click', function() {
ngModelCtrl.$setViewValue(2);
});
}
};
}]);

ngModel前可以使用 ?^ 两个前缀
? - 不要抛出异常。这使这个依赖变为一个可选项
^ - 允许查找父元素的controller

ngModelCtrl.$setViewValue 可改变 controller 中 ng-model 的值

自定义表单验证 $setValidity

1
2
3
.has-error{
border: 1px solid red;
}
1
2
3
4
5
6
7
<div ng-controller="TestCtrl">
<form name="form" novalidate>
<input type="text" ng-model="user.name" name="username" custom-rule ng-class="{'has-error': form.username.$invalid}">
<input type="text" ng-model="user.phone">
<button ng-click="save()">save</button>
</form>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
app.controller('TestCtrl', ['$scope', function($scope) {
$scope.user = {};
$scope.save = function(){
var form = $scope.form;
if(form.username.$invalid){
alert('username不可用');
return false;
}else{
alert('username可用');
}
}
}]);

app.directive('customRule', [function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, iElement, iAttrs, ngModelCtrl) {
iElement.bind('blur',function(){
if(ngModelCtrl.$modelValue != 'xwill'){
ngModelCtrl.$setValidity("customRule", false);
}else{
ngModelCtrl.$setValidity("customRule", true);
}
});
}
};
}]);

首先需要将默认的表单验证禁止 novalidate,设置 form 的 name 字段能让 controller 中通过 $scope.form 取到表单
在 username 字段中自定义验证规则 custom-rule,然后在 customRule 指令中规定只有输入为 xwill 时,表单才可用
在 controller 中可以使用 form.$invalid 判断表单是否可用,form.username.$invalid 判断某字段是否可用

$formatters 和 $parses

1
2
3
4
5
<div ng-controller="TestCtrl">
<input text-transform="uppercase" ng-model="text">
<p>{{text}}</p>
<button ng-click="change()">change</button>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
app.controller('TestCtrl', ['$scope', function($scope) {}]);
app.directive('textTransform', function() {
var transformConfig = {
uppercase: function(input) {
return input.toUpperCase();
},
capitalize: function(input) {
return input.replace(
/([a-zA-Z])([a-zA-Z]*)/gi,
function(matched, $1, $2) {
return $1.toUpperCase() + $2;
});
},
lowercase: function(input) {
return input.toLowerCase();
}
};
return {
require: 'ngModel',
link: function(scope, element, iAttrs, modelCtrl) {
var transform = transformConfig[iAttrs.textTransform];
if (transform) {
// $formatters 只改变 view 中的值
// modelCtrl.$formatters.push(function(input) {
// return transform(input || "");
// });

// $parsers 会改变 controller 中 ng-model 的值
modelCtrl.$parsers.push(function(input) {
return transform(input || "");
});

element.css("text-transform", iAttrs.textTransform);
}
}
};
});

这两个方法常用于输入小写,强制转为大写;输入负数转为0,等等~
$formatters 和 $parses 的区别