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? ivaynberg.github.io/select2 This has already been wrapped as Angular directive: github.com/angular-ui/ui-select2– vspCommentedJun 6, 2013 at 14:47
- 1ui-select2 has now been deprecated. Use github.com/angular-ui/ui-select.– John LeeCommentedJan 19, 2017 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
- 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?CommentedOct 14, 2013 at 2: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 allowmultiple
.– Ethan WuCommentedOct 15, 2013 at 0:19 - mine looks like this ... <select ng-if="event.guests.length" class="multiselect" ng-options="guest.id as (guest.name | truncate:40) for guest in event.guests" data-placeholder="No Guests Selected" ng-model="guestSelection" multiple="multiple" table="table" multiselect-table-dropdown> </select>CommentedOct 15, 2013 at 3:27
- 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.CommentedOct 15, 2013 at 3:39
- 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 WuCommentedJan 31, 2014 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.
- 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'?CommentedJun 6, 2013 at 6: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".– laurentCommentedJun 6, 2013 at 7:45 - @Laurent Sorry, but I haven't really known what to do next :|CommentedJun 6, 2013 at 13:49
- @OcChuojDau, well for a start, does the code make sense at all? :) If it doesn't, what is it you don't understand?– laurentCommentedJun 6, 2013 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!CommentedJun 6, 2013 at 17:55
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'); }); } }; });