I want to use Bootstrap Multiselect Dropdown http://davidstutz.github.io/bootstrap-multiselect/ in AngularJS. I hear that it's necessary to move it to Directive. But I think it's quite complicated & don't know what I have to do. If you have experienced, please guide me! Tks.
-
4Do you need to use the bootstrap multi-select, or can you use select2? http://ivaynberg.github.io/select2/ This has already been wrapped as Angular directive: https://github.com/angular-ui/ui-select2 – vsp Jun 06 '13 at 14:47
-
1ui-select2 has now been deprecated. Use https://github.com/angular-ui/ui-select. – John Lee Jan 19 '17 at 21:04
3 Answers
Here is a directive I use in my project. It works on Chrome and Firefox. You can change the options based on your own need.
angular.module('yourApp')
.directive('yourDirective', function () {
return {
link: function (scope, element, attrs) {
element.multiselect({
buttonClass: 'btn',
buttonWidth: 'auto',
buttonContainer: '<div class="btn-group" />',
maxHeight: false,
buttonText: function(options) {
if (options.length == 0) {
return 'None selected <b class="caret"></b>';
}
else if (options.length > 3) {
return options.length + ' selected <b class="caret"></b>';
}
else {
var selected = '';
options.each(function() {
selected += $(this).text() + ', ';
});
return selected.substr(0, selected.length -2) + ' <b class="caret"></b>';
}
}
});
// Watch for any changes to the length of our select element
scope.$watch(function () {
return element[0].length;
}, function () {
element.multiselect('rebuild');
});
// Watch for any changes from outside the directive and refresh
scope.$watch(attrs.ngModel, function () {
element.multiselect('refresh');
});
}
};
});
Update two snippets for the directive which working on AngularJS v1.3.15 and bootstrap-multiselect v0.9.6: JavaScript, CoffeeScript

- 938
- 9
- 17
-
this works great for me EXCEPT on firefox. When the buttonText function is called after I select something in firefox, the length is always zero, so it doesnt update the text shown. Thoughts? – Luke Ollett Oct 14 '13 at 02:24
-
@LukeOllett It works in my project on both Chrome and Firefox. I guess there might be some issues in the HTML file. In select tag, I use `ng-options` and allow `multiple`. – Ethan Wu Oct 15 '13 at 00:19
-
-
looks like the repo was updated recently with a similar bug fix and my problem has been resolved. thanks for following up and this solution. – Luke Ollett Oct 15 '13 at 03:39
-
@LukeOllett I reached the similar situation before. That snippet works perfectly and suddenly fails for no reason. It turned out some updated changes cause the problem. – Ethan Wu Oct 15 '13 at 17:53
-
hi! is it possible to use this directive in combination with the ui-bootstrap directives? the dropdown directive seems not work or to compile. any ideas ? – MrMuh Jan 27 '14 at 23:12
-
1@MrMuh Actually, I don't know. I use ui-bootstrap in my project too. But I don't use the drop-down directive with this one together. I think you don't need the drop-down directive to create a drop-down list if you are using Bootstrap Multiselect Dropdown. – Ethan Wu Jan 31 '14 at 22:19
If you don't need to create code that's very re-usable, it's actually not that complicated. The first step is to create a basic directive and to get the DOM element:
angular.module('yourapp', [])
.directive('multiselectDropdown', [function() {
return function(scope, element, attributes) {
element = $(element[0]); // Get the element as a jQuery element
// Below setup the dropdown:
element.multiselect({
option1: 123,
option2: "abcd",
// etc.
})
// Below maybe some additional setup
}
}]);
Basically, once you are within the directive, it's actually just regular jQuery or JS code.
Then in your HTML code:
<select multiselectDropdown >
<option value="1">One</option>
<option value="2">One</option>
<option value="3">One</option>
</select>
You can also specify additional attributes on the DIV and get the values using the attributes
parameter of the directive.

- 88,262
- 77
- 290
- 428
-
7Just as an addon this is an excellent model for all jquery plugins you want to migrate to AngularJS. Shouldn't your 'multiselectDropdown' be 'multiselect-dropdown'? – Michael J. Calkins Jun 06 '13 at 06:08
-
1Actually, the latest version of AngularJS supports many way to assign directives in HTML, I think `multiselect-dropdown`, `multiselectdropdown`, `data-multiselect-dropdown`, `class="multiselect-dropdown"` (and probably more) are all valid. "multiselect-dropdown" might indeed be more proper HTML than "multiselectDropdown". – laurent Jun 06 '13 at 07:45
-
-
@OcChuojDau, well for a start, does the code make sense at all? :) If it doesn't, what is it you don't understand? – laurent Jun 06 '13 at 14:54
-
@Laurent To me, Directive is being a very difficult & big aspect :| Could you please help me to write the code in more details in this situation? I really appreciate! – Oc Chuoj Dau Jun 06 '13 at 17:55
-
@OcChuojDau, actually the code above is pretty much all of it, all you need to do now is setup the options in `element.multiselect()`. If there's something not working for you, you need to be more specific about what it is. – laurent Jun 07 '13 at 01:30
-
@Laurent I haven't understood which type of options put into element.multiselect(). Could u pls tell me a little more detailed? – Oc Chuoj Dau Jun 10 '13 at 14:06
-
@OcChuojDau, just try with no options for a start, then add the options you need based on the page you linked - http://davidstutz.github.io/bootstrap-multiselect/ – laurent Jun 10 '13 at 16:02
-
@Laurent Please check for me. My ng-repeat set in is not displayed :( http://plnkr.co/edit/NGQZmW?p=preview – Oc Chuoj Dau Jun 11 '13 at 11:12
Here is my take on Ethan Wu's answer. I fixed a couple of bugs and added options that are overridable on the element: <select multi-select includeSelectAllOption="true" enableFiltering="true" enableClickableOptGroups="true" enableCollapsibleOptGroups="true" multiple ng-model="vm.selectedPlants" ng-options="plant.name group by plant.operatingCompanyName for plant in vm.plants"></select>
// AngularJS: 1.5.8
// bootstrap-multiselect: 0.9.13
angular.module('SocoApp')
.directive('multiSelect', function () {
return {
link: function (scope, element, attrs: any) {
var options: any = {
onChange: function (optionElement, checked) {
if (optionElement != null) {
$(optionElement).removeProp('selected');
}
if (checked) {
$(optionElement).prop('selected', 'selected');
}
element.change();
}
};
//attrs are lowercased by Angular, but options must match casing of bootstrap-multiselect
if (attrs.enablehtml) options.enableHTML = JSON.parse(attrs.enablehtml); //default: false
if (attrs.buttonclass) options.buttonClass = attrs.buttonclass; //default: 'btn btn-default'
if (attrs.inheritclass) options.inheritClass = JSON.parse(attrs.inheritclass); //default: false
if (attrs.buttonwidth) options.buttonWidth = attrs.buttonwidth; //default: 'auto'
if (attrs.buttoncontainer) options.buttonContainer = attrs.buttoncontainer; //default: '<div class="btn-group" />'
if (attrs.dropright) options.dropRight = JSON.parse(attrs.dropright); //default: false
if (attrs.dropup) options.dropUp = JSON.parse(attrs.dropup); //default: false
if (attrs.selectedclass) options.selectedClass = attrs.selectedclass; //default: 'active'
if (attrs.maxheight) options.maxHeight = attrs.maxheight; //default: false, // Maximum height of the dropdown menu. If maximum height is exceeded a scrollbar will be displayed.
if (attrs.includeselectalloption) options.includeSelectAllOption = JSON.parse(attrs.includeselectalloption); //default: false
if (attrs.includeselectallifmorethan) options.includeSelectAllIfMoreThan = attrs.includeselectallifmorethan; //default: 0
if (attrs.selectalltext) options.selectAllText = attrs.selectalltext; //default: ' Select all'
if (attrs.selectallvalue) options.selectAllValue = attrs.selectallvalue; //default: 'multiselect-all'
if (attrs.selectallname) options.selectAllName = JSON.parse(attrs.selectallname); //default: false
if (attrs.selectallnumber) options.selectAllNumber = JSON.parse(attrs.selectallnumber); //default: true
if (attrs.selectalljustvisible) options.selectAllJustVisible = JSON.parse(attrs.selectalljustvisible); //default: true
if (attrs.enablefiltering) options.enableFiltering = JSON.parse(attrs.enablefiltering); //default: false
if (attrs.enablecaseinsensitivefiltering) options.enablecaseinsensitivefiltering = JSON.parse(attrs.enableCaseInsensitiveFiltering); //default: false
if (attrs.enablefullvaluefiltering) options.enableFullValueFiltering = JSON.parse(attrs.enablefullvaluefiltering); //default: false
if (attrs.enableclickableoptgroups) options.enableClickableOptGroups = JSON.parse(attrs.enableclickableoptgroups); //default: false
if (attrs.enablecollapsibleoptgroups) options.enableCollapsibleOptGroups = JSON.parse(attrs.enablecollapsibleoptgroups); //default: false
if (attrs.filterplaceholder) options.filterPlaceholder = attrs.filterplaceholder; //default: 'Search'
if (attrs.filterbehavior) options.filterBehavior = attrs.filterbehavior; //default: 'text', // possible options: 'text', 'value', 'both'
if (attrs.includefilterclearbtn) options.includeFilterClearBtn = JSON.parse(attrs.includefilterclearbtn); //default: true
if (attrs.preventinputchangeevent) options.preventInputChangeEvent = JSON.parse(attrs.preventinputchangeevent); //default: false
if (attrs.nonselectedtext) options.nonSelectedText = attrs.nonselectedtext; //default: 'None selected'
if (attrs.nselectedtext) options.nSelectedText = attrs.nselectedtext; //default: 'selected'
if (attrs.allselectedtext) options.allSelectedText = attrs.allselectedtext; //default: 'All selected'
if (attrs.numberdisplayed) options.numberDisplayed = attrs.numberdisplayed; //default: 3
if (attrs.disableifempty) options.disableIfEmpty = JSON.parse(attrs.disableifempty); //default: false
if (attrs.disabledtext) options.disabledText = attrs.disabledtext; //default: ''
if (attrs.delimitertext) options.delimiterText = attrs.delimitertext; //default: ', '
element.multiselect(options);
// Watch for any changes to the length of our select element
scope.$watch(function () {
//debugger;
return element[0].length;
}, function () {
scope.$applyAsync(element.multiselect('rebuild'));
});
// Watch for any changes from outside the directive and refresh
scope.$watch(attrs.ngModel, function () {
element.multiselect('refresh');
});
}
};
});

- 7,594
- 14
- 69
- 109