(Disclaimer: I don't really know if this question fits the * definition of 'question', since I already have (more than) one solution for the problem, I just don't like the solutions I've found. I apologize in advance if it happens to be so, and welcome alternatives.)
(免责声明:我真的不知道这个问题是否符合'问题'的*定义,因为我已经有(不止一个)解决问题的方法,我只是不喜欢我找到的解决方案。我道歉如果碰巧是这样的话,提前做好选择。)
I'm creating an Angularjs Directive and I'd like to use the Controller as ctrl
syntax so that I can have ctrl.property
in my HTML, instead of a non-contextual, possibily-shadowing property
.
我正在创建一个Angularjs指令,我想将Controller用作ctrl语法,这样我就可以在我的HTML中使用ctrl.property,而不是非上下文,可能阴影属性。
However, this implies that, on the Controller function, variables to be accessed in the HTML need to be bound to this
. For example:
但是,这意味着,在Controller函数中,要在HTML中访问的变量需要绑定到此。例如:
<!-- HTML file: greetings.html -->
<ul>
<li ng-repeat="item in main.items track by $index" ng-bind="item"></li>
</ul>
angular.module('GreetingModule').directive('greetings', function() {
'use strict;'
return {
restrict: 'E',
templateUrl: 'greetings.html',
controller: function () {
this.greetings = ['Hello', 'Hola', 'Salut'];
},
controllerAs: main
}
});
I'm very okay with this. But things fall apart when I start to use functions.
我对此非常好。但是当我开始使用函数时,事情就会崩溃。
Let's say I need to load the greetings from a service.
假设我需要从服务中加载问候语。
angular.module('GreetingModule').directive('greetings',
['langService', function(langService) {
'use strict;'
return {
restrict: 'E',
templateUrl: 'greetings.html',
controller: function () {
this.greetings = [];
function languagesLoaded(langs) {
for (var i = 0; i < langs.length; i++) {
this.greetings.push(langs[i].greeting);
}
}
langService.load({
callback: languagesLoaded
});
},
controllerAs: 'main'
};
}]);
This will fail. At the time of the callback, when languagesLoaded
is called, this
is not bound and the function will throw an error, this.greetings is undefined
.
这将失败。在回调时,当调用languagesLoaded时,这不受约束,并且函数将抛出错误,this.greetings未定义。
I've found three ways around this, but I dislike all three (I don't really have any technical reason for disliking them, they just feel wrong, like I'm trying to do something I'm not supposed to):
我已经找到了三种解决方法,但我不喜欢这三种方式(我真的没有任何技术理由不喜欢它们,它们只是感觉不对,就像我正在尝试做一些我不应该做的事情):
- Create a variable pointing to
this
and use that in the function:
创建一个指向此的变量并在函数中使用它:
var self = this;
// ...
self.greetings.push(langs[i].greeting);
- Passing
this
in the object argument tolangService.load()
:
将对象参数中的this传递给langService.load():
/* In the directive */
langService.load({
target: this,
callback: languagesLoaded
})
/* In the service */
function load(config) {
// load languages, then:
config.languagesLoaded.call(target, languages);
}
- Binding the array both to
this
and to the function scope, so that changing the scope variable also affects thethis
variable (since they reference the same array):
将数组绑定到this和函数作用域,以便更改作用域变量也会影响this变量(因为它们引用相同的数组):
var greetings = this.greetings = [];
// ...
greetings.push(langs[i].greeting);
Is there any other way around this? Assuming there isn't one, which of the above solutions would be the most correct one?
还有其他方法吗?假设没有一个,上述哪个解决方案最正确?
2 个解决方案
#1
1
You can bind the function's this
to the controller:
您可以将函数绑定到控制器:
langService.load({
callback: languagesLoaded.bind(this)
});
For IE < 9 a polyfill would be needed because bind
is available as of ECMAScript 5.
对于IE <9,将需要填充,因为从ECMAScript 5开始可以使用绑定。
#2
1
Your approach #1 seems the best. You should be careful when using this
since it changes its meaning based on its context, for example, like in a function. Sometimes you wouldn't even know this, if you are using a 3rd party library.
你的方法#1似乎是最好的。使用它时应该小心,因为它会根据其上下文更改其含义,例如,在函数中。如果您使用的是第三方库,有时您甚至不知道这一点。
I find this guide useful. From the guide:
我发现本指南很有用。从指南:
function Customer() {
var vm = this;
vm.name = {};
vm.sendMessage = function() { };
}
#1
1
You can bind the function's this
to the controller:
您可以将函数绑定到控制器:
langService.load({
callback: languagesLoaded.bind(this)
});
For IE < 9 a polyfill would be needed because bind
is available as of ECMAScript 5.
对于IE <9,将需要填充,因为从ECMAScript 5开始可以使用绑定。
#2
1
Your approach #1 seems the best. You should be careful when using this
since it changes its meaning based on its context, for example, like in a function. Sometimes you wouldn't even know this, if you are using a 3rd party library.
你的方法#1似乎是最好的。使用它时应该小心,因为它会根据其上下文更改其含义,例如,在函数中。如果您使用的是第三方库,有时您甚至不知道这一点。
I find this guide useful. From the guide:
我发现本指南很有用。从指南:
function Customer() {
var vm = this;
vm.name = {};
vm.sendMessage = function() { };
}