Controller As
angular
.module('app', [])
.controller('DemoController', DemoController);
function DemoController() {
this.name = 'XL';
this.sayName = function() {
return this.name;
}
}
<div ng-controller='DemoController as vm'>
{{vm.name}}
</div>
在js部份誊写控制器的时刻,更像是在写组织函数,然后在view层
实例化一个ViewModule
。那末在view
内里能够直接挪用挂载在这个vm上的属性和要领。
如许的写法的优点就是防止在嵌套的controller
内里运用$parent
去猎取父controller
内里的要领或值。由于在angular内里scope是基于原型举行继续的。
<div ng-controller='parentController'>
{{name}}
<div ng-controller='childController'>
{{name}}
</div>
</div>
angular
.module('app')
.controller('parentController', parentController)
.controller('childController', childController);
//都运用的揣摸式注入
function parentController($scope) {
$scope.name = 'XL';
}
function childController($scope) {
$scope.name = 'xl';
}
末了在视图内里输出’XL’, ‘xl’。假如我要猎取的是父控制器内里的属性值,那末我只能$scope.$parent
去猎取,嵌套的controller
多了怎么办- -,运用controller as
能够有用的防止这个题目.
假如运用这类controller as
的写法的话,只管防止在controller内里运用$scope,除非碰到$emit,$broadcase,$on, $watch
。
<input ng-model='vm.title'>
function SomeController($scope, $log) {
var vm = this;
vm.title = 'Some Title';
$scope.$watch('vm.title', function(current, original) {
$log('vm.title was %s', original);
$log('vm.title is now %s', current);
});
}
this vs $scope
angular
.module('app', [])
.controller('parentController', parentController);
function parentController($scope) {
this.sayName = function() {
console.log('this');
}
}
<div ng-controller='parentController as vm'>
<button ng-click='vm.sayName()'>BtnA</button>
<button ng-click='sayName()'>BtnB</button>
</div>
效果:
点击
BtnA
后能输出'this'
,点击
BtnB
后不输出任何东西。
事实上:
当誊写Controller
的时刻,即在写controller constructor
,运用controller as
语法,当在view
内里实例化controller
后(vm),this
便指向这个实例化vm
,然后就能够在view
内里挪用vm
所具有的属性和要领。在本例中即vm
所具有的sayName()
要领
假如
function parentController($scope) {
this.sayName = function() {
console.log('this');
}
$scope.sayName = function() {
console.log('$scope');
}
}
在controller constructor
内里定义$scope.sayName
要领,那末点击BtnB
的时刻能够输出$scope
。
事实上:
注入$scope
后,即供应了一个model
,能够在这个model
上面绑定属性和要领。那末在view
内里声明的controller
内里能够接见到。
综上,在this
上面挂载的要领实际上是在controller constructor
上面挂载的要领,必需要经由过程controller
实例去接见。在$scope上面挂载的要领是在模子上面挂载的,由于在directive的pre-link阶段(见下面的compile vs link)是将$scope绑定到DOM上,因而能够直接在view层
接见绑定在$scope
的要领。
除此之外,this
和$scope
别的一个区分就是指向的题目:
<div ng-controller='parentController' id='parentBox'>
<p ng-click='logThisAndScope()'>log 'this' and $scope</p> - parent scope
<div ng-controller='childController' id='childBox'>
<p ng-click='logThisAndScope()'>log 'this' and $scope</p> - child scope
</div>
</div>
然后仅仅在parentController
上面挂载要领:
$scope.logThisAndScope = function() {
console.log(this, $scope);
}
起首由于controller
嵌套同时是在$scope
上面挂载要领,因而父元素和子元素点击都邑输出this
和$scope
的内容,在这个实例当中this
的指向是差别的,一个是parentController
别的一个是childController
,$scope
的指向是一样的,同时指向的是绑定在id为parentBox的DOM内的$scope。
The problem with controllerAs in Directives
当运用controllerAs
语法的时刻, controller scope
事实上是绑定到了controller
的this对象
上面。然则在日常平凡我们誊写directive
的时刻会建立自力的作用域。
app.directive('someDirective', function() {
return {
scope: {
oneWay: '@',
twoWay: '=',
expr: '&'
}
}
})
接下来我们建立一个具有自力作用域,有本身的控制器的directive
。
app.directive('someDirective', function() {
return {
scope: {},
controller: function() {
this.name = 'Pascal';
},
controllerAs: 'ctrl',
template: '<div>{{ctrl.name}}</div>'
}
})
然则,假如这个name
属性是一个能够和父作用域同享的呢?固然我们立马想到的是
app.directive('someDirective', function() {
return {
scope: {
name: '='
},
....
}
})
假如外部的name
属性发生变化并不会马上反应到内部的controller
的this对象
上。在1.2版本内里处置惩罚这类状况就是运用$scope效劳
上挂载的$watch
要领去监听name
属性的变化。
app.directive('someDirective', function() {
return {
scope: {
name: '='
},
controller: function($scope) {
this.name = 'Pascal';
$scope.$watch('name', function(newValue){
this.name = newValue;
}.bind(this));
//这个处所要注重this的指向
}
}
})
bindToController
1.3版本内里directive
涌现了一个新的设置对象bindToController
,望文生义绑定到controller
上面,当directive
运用自力作用域以及controllerAs
语法的时刻,而且bindToController
这个值被设置为true
的时刻,这个组件的属性都被绑定到controller上了而不是scope上面。
这意味着,当controller被实例化后,自力作用域上绑定属性的初始值都能够经由过程this对象来接见到,将来这个属性的值发生变化后都能被检测的到。
app.directive('someDirective', function () {
return {
scope: {
name: '='
},
controller: function () {
this.name = 'Pascal';
},
controllerAs: 'ctrl',
bindToController: true,
template: '<div>{{ctrl.name}}</div>'
};
});
1.4版本的语法晋级:
在1.3版本bindToController
为boolen
值,在1.4版本中为一个对象,即假如想将自力作用域上的值绑定到controller
上面,能够直接在bindToController
这个对象上举行设置。
app.directive('someDirective', function () {
return {
scope: {},
bindToController: {
someObject: '=',
someString: '@',
someExpr: '&'
},
controller: function () {
this.name = 'Pascal';
},
controllerAs: 'ctrl',
template: '<div>{{ctrl.name}}{{ctrl.someObject}}</div>'
};
});
//假如父作用域内里的someObject属性发生变化,会随时反应到这个directive的template内里。
complie vs link
Angularjs在处置惩罚directive
时,取决于本身的compile
和link
参数定义的划定规矩:
当定义directive
的时刻同时定义了complie
,pre-link
,post-link
3个参数的时刻
<level-one>
<level-two>
Hello {{XL}}
<level-three>
Hello {{Sugar}}
<level-three>
<level-two>
</level-one>
var app = angular.module('app', []);
function createDirective(name) {
return function() {
return {
restrict: 'E',
compile: function(tElem, tAttrs) {
console.log(name + ': complie');
},
return {
pre: function(scope, tElem, iAttrs) {
console.log(name + ': pre link');
},
post: function(scope, tElem, iAttrs) {
console.log(name + ': post link');
}
}
}
}
}
app.directive('levelOne', createDirective('levelOne'));
app.directive('levelTwo', createDirective('levelTwo'));
app.directive('levelThree', createDirective('levelThree'))
效果:
angularjs一最先compile一切原生指令和自定义指令,complile阶段还没有绑定scope.link阶段分为pre-link和post-link阶段。
从效果看来compile阶段
和pre-link阶段
的递次一样,然则post-link实行递次
恰好相反。
修正代码:
function createDirective(name) {
return function() {
return {
restrict: 'E',
compile: function(tElem, tAttrs) {
console.log(name + ': complie =>' + tElem.html());
},
return {
pre: function(scope, iElem, iAttrs) {
console.log(name + ': pre link =>' + iElem.html());
},
post: function(scope, iElem, iAttrs) {
console.log(name + ': post link =>' + iElem.html());
}
}
}
}
}
效果:
如今再看下输出的信息,特别是在pre-link阶
段,虽然和compile
一样输出元素的递次是一样的,然则元素中涌现了属性class='ng-binding'
,事实上在compile阶段DOM元素仍然是最初html标记所建立的DOM元素,它是模板元素(template element)
的实例元素(instance element)
.pre-link阶段供应一个scope
给这个实体,这个实体能够是全新的scope
,继续的scope
或许是伶仃的scope
,取决于directive定义的scope属性。
post-link阶段
:当实例元素初始化完成(compile阶段)和绑定scope(pre-link阶段)完成后就能够举行post-link(DOM)操纵。注重这个处所实行递次是从子元素最先再到父元素的。即在level-one
实行post-link
阶段前确保level-two.level-three
实行终了。
compile阶段:
/*
* @param tElem - 模板元素
* @param tAttr - 模板元素的属性
*/
compile: function(tElem, tAttrs) {
}
pre-link阶段
/*
* @param scope - 衔接于此的实例的scope
* @param iElem - 实例元素
* @param iAttr - 实例元素的属性
*/
function (scope, iElem, iAttr) {
}
post-link阶段
/*
* @param scope - 衔接于此实例的scope
* @param iElem - 实例元素
* @param iAttr - 实例元素的属性
*/
function (scope, iElem, iAttr) {
}
where to use compile or link?
之前的写法都是直接用link
,默许举行了compile
和pre-link
的阶段,在post-link
内里就能够直接运用绑定在实例上的scope,ele,attrs
。
假如在你的顺序内里不需要运用scope
,不需要$watch
其他的值,仅仅供应模板实例的话,能够直接运用compile
。这个时刻你是不能对DOM有任何操纵的。
除此之外,假如你不需要实例元iElem
,那末也能够不必link函数。
但当你同时誊写compile
和link
函数(pre-link或许post-link)
的时刻,肯定要在compile
函数内里返回link
函数,由于假如compile
被定义的时刻link
属性被忽略了。