如何将变量分配给函数内的别名控制器?

时间:2022-01-28 16:00:17

(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):

我已经找到了三种解决方法,但我不喜欢这三种方式(我真的没有任何技术理由不喜欢它们,它们只是感觉不对,就像我正在尝试做一些我不应该做的事情):

  1. Create a variable pointing to this and use that in the function:
  2. 创建一个指向此的变量并在函数中使用它:

    var self = this;
    // ...
    self.greetings.push(langs[i].greeting);
  1. Passing this in the object argument to langService.load():
  2. 将对象参数中的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);
    }
  1. Binding the array both to this and to the function scope, so that changing the scope variable also affects the this variable (since they reference the same array):
  2. 将数组绑定到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() { };
}