AngularJS MultiSelect

An AngularJS directive which creates a dropdown button with multiple or single selections. Fully configurable through element attributes and CSS.
Version: 2.0.1



  View on Github

Features

For the upcoming version:

Usage

Include the required files
<link rel="stylesheet" href="angular-multi-select.css">
...
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="angular-multi-select.js"></script>      
...
Load the multi-select directive into your AngularJS app, such as:
var myApp = angular.module('myApp', [ 'multi-select' ]);
In your controller, prepare a $scope variable as the input-model
$scope.modernWebBrowsers = [
    { icon: "<img src=[..]/opera.png.. />",               name: "Opera",              maker: "(Opera Software)",        ticked: true  },
    { icon: "<img src=[..]/internet_explorer.png.. />",   name: "Internet Explorer",  maker: "(Microsoft)",             ticked: false },
    { icon: "<img src=[..]/firefox-icon.png.. />",        name: "Firefox",            maker: "(Mozilla Foundation)",    ticked: true  },
    { icon: "<img src=[..]/safari_browser.png.. />",      name: "Safari",             maker: "(Apple)",                 ticked: false },
    { icon: "<img src=[..]/chrome.png.. />",              name: "Chrome",             maker: "(Google)",                ticked: true  }
]; 
In your view, set the directive as an attribute
<div     
    multi-select
    input-model="modernWebBrowsers"
    button-label="icon name"
    item-label="icon name maker"
    tick-property="ticked"
>
</div>
... or as an element, but be careful with browser compatibility.
<multi-select    
    input-model="modernWebBrowsers"    
    button-label="icon name"
    item-label="icon name maker"
    tick-property="ticked"
>
</multi-select>
And that's it! You should now have dropdown button like the one you saw earlier on top of the page.

To get the selected items:
angular.forEach( $scope.modernWebBrowsers, function( value, key ) {
    if ( value.ticked === true ) {
        /* do your stuff here */
    }
});

Attributes / Options

Full spec
<div 
    multi-select 
    input-model="$scope.arrOfObjects"
    output-model="$scope.arrOfObjects2"
    button-label="property1 property2 ..."         
    item-label="property1 property2 ..." 
    tick-property="property3" 
    disable-property="property4"
    orientation="horizontal | vertical"
    selection-mode="multiple | single"
    max-labels="999"     
    directive-id="..."
    is-disabled="true | false"
    helper-elements="all none reset filter"
    default-label="..."
    on-open="$scope.functionOpen( data )"
    on-close="$scope.functionClose( data )"
    on-item-click="$scope.functionClick( data )"
>
</div>
.. or ..
<multi-select 
    ...
>
</multi-select>
 
Below are the available attributes to configure the multi-select directive:

Demo

Look at the $scope input-models to see the values getting updated as you select / deselect a checkbox.

Icons in the objects are actually HTML img tag ( <img src="full_path" ... /> ), shortened for simplicity.

1) Minimum



code
<div
    multi-select
    input-model="modernWebBrowsers"
    button-label="icon name"
    item-label="icon name maker"
    tick-property="ticked"
>
</div>
input-model
$scope.modernWebBrowsers = [
  { icon: {{removeHost(row.icon)}}, name: {{row.name}}, maker: {{row.maker}}, ticked: {{row.ticked}} },
];


2) Full


*Open your console to see the multi-select event callbacks. Note that the events might be triggered differently across different browsers.

code
<div 
    multi-select 
    input-model="modernWebBrowsers2"
    output-model="resultData"
    button-label="icon name"         
    item-label="icon name maker" 
    tick-property="ticked" 
    disable-property="checkboxDisabled"
    orientation="horizontal"
    selection-mode="multiple"
    max-labels="2"     
    directive-id="multiSelectFull"
    is-disabled="false"
    helper-elements="all none filter reset"
    default-label="Please select one"
    on-open="open( data )"
    on-close="close( data )"
    on-item-click="click( data )"
>
</div>
input-model
$scope.modernWebBrowsers2 = [
  { icon: {{removeHost(row.icon)}}, name: {{row.name}}, maker: {{row.maker}}, ticked: {{row.ticked}} },
];

output-model (Will list all with "ticked" === true)
$scope.resultData = [
  { icon: {{removeHost(row.icon)}}, name: {{row.name}}, maker: {{row.maker}}, ticked: {{row.ticked}} },
];

3) Update input model on the fly




* You can also update a single item. Something like.. $scope.modernBrowsers[ 1 ].ticked = false or $scope.modernBrowsers[ 1 ].name = 'Hola!'

code
<div 
    multi-select 
    input-model="dynamicData"
    button-label="icon name"         
    item-label="icon name maker" 
    tick-property="ticked" 
>
</div>
input-model
$scope.dynamicData = [
  { icon: {{removeHost(row.icon)}}, name: {{row.name}}, maker: {{row.maker}}, ticked: {{row.ticked}} },
];

4) Enable / disable multi-select & granular control


$scope.granDisabled = {{granDisabled}}

code
<div 
    multi-select 
    input-model="granWebBrowsers"
    button-label="icon name"         
    item-label="icon name maker" 
    tick-property="ticked" 
    disable-property="checkboxDisabled"
    is-disabled="granDisabled"
>
</div>
input-model
* take note that checkboxes with "checkboxDisabled" === true will always be disabled regardless of the $scope.granDisabled value.

$scope.granWebBrowsers = [
  { icon: {{removeHost(row.icon)}}, name: {{row.name}}, maker: {{row.maker}}, ticked: {{row.ticked}}, checkboxDisabled: {{row.checkboxDisabled}} },
];

5) Single selection mode with no helper elements, just like a normal drop down menu.


Even if you put multiple "ticked" === true, it will smartly tick only one item at a time.



code
<div 
    multi-select 
    input-model="singleWebBrowsers"
    button-label="icon name"         
    item-label="icon name maker" 
    tick-property="ticked" 
    selection-mode="single"
    helper-elements=""
>
</div>
input-model
$scope.singleWebBrowsers = [
  { icon: {{removeHost(row.icon)}}, name: {{row.name}}, maker: {{row.maker}}, ticked: {{row.ticked}} },
];

6) Grouping

Vertical (default) grouping:

Horizontal grouping:

In your multi-select code, set group markers by using attribute group-property. In your input-model, specify start and end points of a group using this group-property.
For example, to get the result above, you use:

code
<div 
    multi-select 
    input-model="webBrowsersGrouped"
    button-label="icon name"         
    item-label="icon name maker" 
    tick-property="ticked" 
    orientation="vertical" <!-- or horizontal -->
    group-property="multiSelectGroup"     
>
</div>
input-model (For simplicity, input model below is static. The ticked property will not change)
$scope.webBrowsersGrouped = [
    {
        name: '<strong>All Browsers</strong>',
        multiSelectGroup: true
    },
    {
        name: '<strong>Modern Web Browsers</strong>',
        multiSelectGroup: true
    },
    { 
        icon: '<img  src="https://cdn1.iconfinder.com/data/icons/fatcow/32/opera.png" />',                         
        name: 'Opera',              
        maker: '(Opera Software)',        
        ticked: true
    },
    { 
        icon: '<img  src="https://cdn1.iconfinder.com/data/icons/fatcow/32/internet_explorer.png" />',             
        name: 'Internet Explorer',  
        maker: '(Microsoft)',
        ticked: false   
    },
    { 
        icon: '<img  src="https://cdn1.iconfinder.com/data/icons/humano2/32x32/apps/firefox-icon.png" />',         
        name: 'Firefox',            
        maker: '(Mozilla Foundation)',    
        ticked: true    
    },
    { 
        icon: '<img  src="https://cdn1.iconfinder.com/data/icons/fatcow/32x32/safari_browser.png" />',             
        name: 'Safari',             
        maker: '(Apple)',                 
        ticked: false   
    },
    { 
        icon: '<img  src="https://cdn1.iconfinder.com/data/icons/google_jfk_icons_by_carlosjj/32/chrome.png" />',  
        name: 'Chrome',             
        maker: '(Google)',                
        ticked: true   
    },
    {
        multiSelectGroup: false
    },
    {
        name: '<strong>Classic Web Browsers</strong>',
        multiSelectGroup: true
    },
    { 
        icon: '<img  src="http://www.ucdmc.ucdavis.edu/apps/error/nojavascript/images/netscape_icon.jpg" />',      
        name: 'Netscape Navigator', 
        maker: '(Netscape Corporation)',  
        ticked: true    
    },
    { 
        icon: '<img  src="http://upload.wikimedia.org/wikipedia/en/thumb/f/f4/Amaya_logo_65x50.png/48px-Amaya_logo_65x50.png" />',             
        name: 'Amaya',  
        maker: '(Inria & W3C)',             
        ticked: true   
    },
    {
        icon: '<img  src="http://upload.wikimedia.org/wikipedia/commons/8/8c/WorldWideWeb_Icon.png" />',
        name: 'WorldWideWeb Nexus',
        maker: '(Tim Berners-Lee)',
        ticked: false
    },
    {
        multiSelectGroup: false
    },
    {
        multiSelectGroup: false
    }
];    
Note on grouping:

Dependency

AngularJS v1.2.15. Other versions may or may not work. Please test first.

Browser Compatibility

Tested on:

Bug Reporting

Note

Licence

Released under the MIT license:

The MIT License (MIT)

Copyright (c) 2014 Ignatius Steven (https://github.com/isteven)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE