如何在 Angular select 指令应用模型更改后调用 JQuery 方法?

How to invoke a JQuery method after Angular select directive applies a model change?

我正在尝试通过 Angular ng-model:

更改 David Stutz 的 bootstrap-multiselect 的 selection
<select ng-model="selection" multiple="multiple" id="my-example">
  <option value="cheese">Cheese</option>
  <option value="tomatoes">Tomatoes</option>
  <option value="mozarella">Mozzarella</option>
  <option value="mushrooms">Mushrooms</option>
  <option value="pepperoni">Pepperoni</option>
  <option value="onions">Onions</option>
</select>

对模型的更改仅应用于基础 select 元素,但 bootstrap-multiselect 不会自动更新。查看它的 documentation,这是预料之中的:之后您需要调用 multiselect('refresh') 来传播更改:

$('#my-example').multiselect('refresh');

我的问题是:

How to invoke this method when the model changes after Angular is done updating the select element?

因为我需要访问元素,所以我假设指令是可行的方法。我正在查看 decorators,理论上我可以使用它来修改内置 select 指令的行为,但我不知道如何在正确的时刻调用我的代码。

我准备了一个 plunk 来演示这个问题:

我认为您不应该混合使用(为什么在数据处于 angular 的监视周期时使用 jquery 刷新数据?)。你可以用你的选项做这样的事情:

<option ng-value="Cheese.val">{{Cheese.text}}</option>
<option ng-value="Tomatoes.val">{{Tomatoes.text}}</option>

然后用 Angular 处理其余部分(对于 angular + 多选可能 google)

最后我设法用装饰器解决了我的问题。我基于 Directive Decorator Example in AngularJS documentation.

与示例中的 ngHrefDirective 不同,selectDirective 定义了 preLinkpostLink,因此 compile 覆盖也必须 return 两者.不过,我只需要更改 postLink,其中定义了 $render。在我的方法版本中,我只是调用原始方法,更新 select 元素,然后调用 multiselect('refresh'),这是我最初的要求:

app.config(['$provide', function($provide) {
  $provide.decorator('selectDirective', ['$delegate', function($delegate) {
    var directive = $delegate[0];

    directive.compile = function() {

      function post(scope, element, attrs, ctrls) {
        directive.link.post.apply(this, arguments);

        var ngModelController = ctrls[1];
        if (ngModelController) {
          originalRender = ngModelController.$render;
          ngModelController.$render = function() {
            originalRender();
            element.multiselect('refresh');
          };
        }
      }

      return {
        pre: directive.link.pre,
        post: post
      };
    };

    return $delegate;
  }]);
}]);