I find myself many times in need of a good, general purpose multiselect dropdown with checkboxes. There are many options for multiselect, like select2, but for some reason having discrete checkboxes is generally overlooked. This is where rolling my own came into play.
EDIT: Be sure to check out the updated info. for this directive. https://long2know.com/2016/05/angular-multiselect-dropdown-updated/
Once upon a time, before Angular, there was a jQuery multiselect plugin, with checkboxes, that I really enjoyed using. It was written by Eric Hynds, and I found myself using it on many projects a few years ago. After a bit of Googling, I also found a wrapper that one developer had started to make this plugin work with Angular. The problem I ran into is that the plugin itself was entirely intended to work with jQuery UI themes. Since every web project I’ve worked on in the past 2-3 years has been based on Bootstrap, using that old jQuery plugin, even with an Angular directive wrapping its functionality, was a non-starter.
My criteria/needs/desires for an Angular directive included most of the functionality provided in the old jQuery plugin: filtering, check/uncheck all, and Angular specifics like two-way binding, proper text labels based on selected items, and, of course, Bootstrap styling. Googling provided a good start rather than writing from scratch. I stumbled upon one directive (author unknown) that was pretty close, but it was based on older Bootstrap (2.3 I think), it was rough, and some of its features were broken. After a bit of retooling, and following the pattern (like it did) of Angular UI’s type-ahead textbox, things started to come together nicely.
In the first pass, I ran into scope issues. Multiple instances of the multiselect dropdown would persist changes across the different ngModels. After a bit of tweaking and comparing my code to Angular UI’s latest, I finally got those issues out of the way. It was also one of those odd weird side effects that I wasn’t sure why it was broken or what really fixed it. The other things that I tweaked were whether or not I wanted complex models, or discrete values, passed to the bound ngModel. Ultimately, I take the simple primitives and persist the selections in the URL using $location.search() in my controllers. Obviously, complex objects aren’t much use in this regard.
For the directive, utilization looks like this:
<div class="form-group"> <multiselect class="input-xlarge multiselect" ng-model="vm.searchProp" options="p.key as p.value for p in vm.options" select-limit="5" header="Select Stuff" selected-header="options selected" multiple="true" required complex-models="false" select-limit-use-filtered ="true" enable-filter="true" filter-placeholder="Filter stuff.."> </multiselect> </div>
The basic attributes are pretty self explanatory. Options defines the expression by which the directive can determine its options to display. This is similar to an expression you’d pass to an ngRepeat. select-limit lets you limit how many items can be checked, multiple indicates whether or not multiple/single select is active, enable-filter indicates whether filtering of the options is available, and the rest of the attributes are mainly for determining what is displayed in the drop-down. It probably isn’t obvious, but select-limit-use-filtered determines whether Check/Uncheck and Check All/UncheckAll only work relative to the filtered selection and/or all items. This is handy in that if someone is looking at a filtered list of options, clicking ‘Check All’ only works on those options which are visible without affecting other options that were selected prior to filtering (ie – not visible). The same is true for ‘Uncheck All.’ The complex-models attributes is as I described previously. This determines whether primitive values (from your expression) are pushed to ngModel or the “complex” models are pushed.
While not pictured above, you can also add a ‘required’ attribute to tie into ngForm validation.
I won’t bore you with pasting a lot of code, since there is a fully working fiddle below from which you can view all of the code. You can also see how it works with multiple multiselect dropdowns in a single view.