如何在 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 来演示这个问题:
- 我有两个绑定到同一个模型的 multiselect:一个 bootstrap-multiselect 和一个普通的
- 我用默认的selection
初始化
- 第一个按钮更改 select离子。普通的 multiselect 立即更新,但 bootstrap-multiselect 看起来没有变化。
- 第二个按钮在警报中显示当前模型值。
- 第三个按钮在 bootstrap-multiselect 上调用
refresh
,导致它更新。这就是我希望 Angular. 自动调用的内容
我认为您不应该混合使用(为什么在数据处于 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
定义了 preLink
和 postLink
,因此 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;
}]);
}]);
我正在尝试通过 Angular ng-model
:
<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 来演示这个问题:
- 我有两个绑定到同一个模型的 multiselect:一个 bootstrap-multiselect 和一个普通的
- 我用默认的selection 初始化
- 第一个按钮更改 select离子。普通的 multiselect 立即更新,但 bootstrap-multiselect 看起来没有变化。
- 第二个按钮在警报中显示当前模型值。
- 第三个按钮在 bootstrap-multiselect 上调用
refresh
,导致它更新。这就是我希望 Angular. 自动调用的内容
我认为您不应该混合使用(为什么在数据处于 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
定义了 preLink
和 postLink
,因此 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;
}]);
}]);