I am trying to change the selection of David Stutz's bootstrap-multiselect via 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>
The changes to the model only get applied to the underlying select
element, but the bootstrap-multiselect doesn't get updated automatically. Looking at its documentation, this is expected: you are required to call multiselect('refresh')
afterwards to propagate the changes:
$('#my-example').multiselect('refresh');
My question is:
How to invoke this method when the model changes after Angular is done updating the
select
element?
Since I need to access the element, I assume directives are the way to go. I was looking at decorators, which in theory I could use to modify the behavior of the built-in select directive, but I don't know how to get my code invoked at the right moment.
I've prepared a plunk to demo the issue:
refresh
on bootstrap-multiselect, which causes it to update. This is what I would like to get called automatically by Angular.In the end I managed to solve my problem with a decorator. I based it on the Directive Decorator Example in AngularJS documentation.
Unlike ngHrefDirective
from the example, selectDirective
defines both preLink
and postLink
, therefore the compile
override must also return both. I only needed to change postLink
though, where $render
is defined. In my version of the method I simply invoked the original method, which updates the select
element, and called multiselect('refresh')
afterwards, which was my original requirement:
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;
}]);
}]);