├── .bowerrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bower.json ├── bowerDocs.json ├── dist ├── angularjs-dropdown-multiselect.min.js ├── index.css ├── maps │ └── angularjs-dropdown-multiselect.min.js.map └── src │ ├── angularjs-dropdown-multiselect.js │ └── index.css ├── docs ├── assets │ ├── body-bg.jpg │ ├── download-button.png │ ├── github-button.png │ ├── header-bg.jpg │ ├── highlight-bg.jpg │ └── sidebar-bg.jpg ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── index.html ├── maps │ └── scripts │ │ ├── app.js.map │ │ └── vendor.js.map ├── scripts │ ├── app.js │ └── vendor.js └── styles │ └── app.css ├── gulp ├── .eslintrc ├── build.js ├── conf.js ├── inject.js ├── scripts.js ├── server.js ├── styles.js ├── unit-tests.js └── watch.js ├── gulpfile.js ├── karma.conf.js ├── package.json └── src ├── app ├── component │ ├── angularjs-dropdown-multiselect.controller.js │ ├── angularjs-dropdown-multiselect.directive.js │ ├── angularjs-dropdown-multiselect.html │ ├── angularjs-dropdown-multiselect.module.js │ └── index.scss ├── index.module.js ├── index.scss ├── main │ ├── main.component.js │ ├── main.controller.js │ ├── main.template.html │ ├── pygment_trac.scss │ └── stylesheet.scss └── v1docs │ ├── v1docs.component.js │ └── v1docs.template.html ├── assets ├── body-bg.jpg ├── download-button.png ├── github-button.png ├── header-bg.jpg ├── highlight-bg.jpg └── sidebar-bg.jpg └── index.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Unix-style newlines with a newline ending every file 2 | [*] 3 | end_of_line = crlf 4 | insert_final_newline = true 5 | indent_style = tab 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "plugins": ["angular"], 4 | "env": { 5 | "es6": true, 6 | "browser": true, 7 | "jasmine": true 8 | }, 9 | "ecmaFeatures": { 10 | "modules": true 11 | }, 12 | "globals": { 13 | "angular": true, 14 | "module": true, 15 | "inject": true, 16 | "Highcharts": true 17 | }, 18 | "rules": { 19 | "linebreak-style": "off", 20 | "no-tabs": "off", 21 | "no-mixed-spaces-and-tabs": "error", 22 | "indent": ["error", "tab", { "SwitchCase": 1 }], 23 | "max-len": ["error", 150], 24 | "no-use-before-define": ["error", "nofunc"] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generic (system) files/extensions we don't want 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | .idea/* 10 | *.DS_Store 11 | lib-cov 12 | pids 13 | logs 14 | results 15 | 16 | node_modules 17 | 18 | #Actually, need to track these for site to run on Github Pages.. 19 | /bower_components 20 | .tmp/ 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Version numbers correspond to `bower.json` version 2 | 3 | # 2.0.0-beta.9 4 | ## Features 5 | - Added setting idProperty, when set comparison will be done by this property instead of by reference 6 | 7 | # 2.0.0-beta.7 8 | 9 | ## Breaking Changes 10 | - bower.json and package.json main are back to the original dist/angularjs-dropdown-multiselect.min.js 11 | - Linking directly to the repository was bad practice and is no longer suported 12 | 13 | # 2.0.0-beta.5 & 2.0.0-beta.6 14 | 15 | ## Features 16 | - Added support for transcluded custom toggle-dropdown element 17 | 18 | # 2.0.0-beta.4 19 | 20 | Small bugFix 21 | 22 | ## Bug Fixes 23 | - orderBy wasn't respecting order in original array #322 24 | 25 | # 2.0.0-beta.3 26 | 27 | Small bugFix 28 | 29 | ## Bug Fixes 30 | - Infinite loop when width is smaller than "..." in smartButtonText 31 | 32 | # 2.0.0-beta.2 33 | 34 | Continuation of the rework of the component. In this version we stop comparing objects by their id property and smiply use reference 35 | 36 | ## Breaking Changes 37 | - dropped support for idProp 38 | - dropped support for externalIdProp 39 | 40 | ## Features 41 | - options array can exist out of any type of object 42 | 43 | ## Bug Fixes 44 | - check all no longer displayed when selectionLimit is defined 45 | 46 | # 2.0.0-beta.1 47 | 48 | We've started a rework of the component and are planning to resolve as many issues as possible, this however means that some breaking changes are needed. We've decided to release some beta versions first in which we'll have the freedom to add more breaking changes. 49 | 50 | ## Breaking Changes 51 | - extraSettings.selectionLimit = 1 is now treated the same as all other values, so selected-model doesn't have to be an object anymore (it should always be an array) 52 | - removed attribute group-by, replaced by setting groupBy 53 | - removed attribute checkboxes, replaced by setting checkBoxes 54 | 55 | ## Features 56 | - Development wise the module has got a makeover which should make it easier to be maintained, before we release 2.0.1 we'll try to make the development experience as nice as possible 57 | - We've also started a refactoring of the component that should make it easier to use and to add new features 58 | - Added the selectedToTop setting. 59 | 60 | ## Bug Fixes 61 | - Fixes #317: Single selection can remove properties from preselected object -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Dotan Simha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This directive gives you a Bootstrap Dropdown with the power of AngularJS directives. 2 | 3 | # Features 4 | - Based on Bootstrap's dropdown. 5 | - jQuery is not necessary. 6 | - Seperated your data and the selection data. no modification to the data made. 7 | - Built-in search. 8 | - Complete control on the selected items model to fit it to your requirements. 9 | - Two view options: normal list and checkboxes. 10 | - Pre-selected values. 11 | - Limit selection count. 12 | - Grouping items by property. 13 | - Callback events. 14 | - Translation texts. 15 | - Scrollable list (useful for big lists) 16 | - Keyboard controls 17 | 18 | ## Demo 19 | http://dotansimha.github.io/angularjs-dropdown-multiselect/ 20 | 21 | ## Dependencies 22 | - required: AngularJS >= 1.5, Bootstrap >= 3.0 23 | 24 | - Make sure to add the dependencies before the directive's js file. 25 | - Note: Bootstrap JS file is not needed for the directive, it just uses the CSS file 26 | 27 | ## Install 28 | 1. Download the files 29 | 1. Using bower: 30 | Just run `bower install angularjs-dropdown-multiselect` 31 | 2. Using npm : 32 | Just run `npm install angularjs-dropdown-multiselect` 33 | 3. Manually: 34 | You can download the `.js` file directly or clone this repository 35 | 2. Include the file in your app 36 | - ``. 37 | - You can also use the minfined version (`angularjs-dropdown-multiselect.min.js`). 38 | 3. Include the module in angular (i.e. in `app.js`) - `angularjs-dropdown-multiselect` 39 | 40 | 41 | ## Contributing 42 | Issues and PR's are much appreciated. We're currently working on reducing them. 43 | When you create a new PR please make it against the develop branch when adding new features and to the fix branch when fixing small issues instead of master. 44 | 45 | ## Usage and Documentation 46 | See the documentation and examples in the GitHub pages: 47 | http://dotansimha.github.io/angularjs-dropdown-multiselect/ 48 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-dropdown-multiselect", 3 | "version": "2.0.0-beta.10", 4 | "authors": [ 5 | "Dotan Simha ", 6 | "Pieter Kempenaers " 7 | ], 8 | "description": "AngularJS Dropdown Multiselect directive", 9 | "keywords": [ 10 | "angular", 11 | "angularjs", 12 | "directive", 13 | "dropdown", 14 | "multiselect", 15 | "checklist", 16 | "list", 17 | "bootstrap", 18 | "checkbox" 19 | ], 20 | "license": "MIT", 21 | "main": "dist/angularjs-dropdown-multiselect.min.js", 22 | "ignore": [ 23 | "**/.*", 24 | "node_modules", 25 | "bower_components", 26 | "test", 27 | "tests" 28 | ], 29 | "dependencies": { 30 | "angular": "~1.5" 31 | }, 32 | "devDependencies": { 33 | "angular-highlightjs": "^0.7.1", 34 | "bootstrap-sass": "~3.3.5", 35 | "angular-mocks": "~1.5.3", 36 | "angular-bootstrap": "~2.1.4", 37 | "angular-ui-router": "~0.4.2" 38 | }, 39 | "resolutions": { 40 | "angular": ">=1.4.0" 41 | }, 42 | "overrides": { 43 | "bootstrap-sass": { 44 | "main": [ 45 | "assets/stylesheets/_bootstrap.scss", 46 | "assets/fonts/**/*" 47 | ] 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bowerDocs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboarddatadisplayingdocs", 3 | "version": "0.0.0", 4 | "authors": [ 5 | "Pieter Kempenaers " 6 | ], 7 | "description": "dashboarddatadisplaying Docs", 8 | "keywords": [ 9 | "angularjs", 10 | "dashboard", 11 | "data", 12 | "documentation" 13 | ], 14 | "private": true, 15 | "dependencies": { 16 | "angular": "~1.5.3", 17 | "bootstrap-sass": "~3.3.5", 18 | "angular-highlightjs": "^0.7.1", 19 | "angular-bootstrap": "~2.1.4", 20 | "angular-ui-router": "~0.4.2" 21 | }, 22 | "devDependencies": { 23 | "angular-mocks": "~1.5.3" 24 | }, 25 | "overrides": { 26 | "bootstrap-sass": { 27 | "main": [ 28 | "assets/stylesheets/_bootstrap.scss", 29 | "assets/fonts/bootstrap/glyphicons-halflings-regular.eot", 30 | "assets/fonts/bootstrap/glyphicons-halflings-regular.svg", 31 | "assets/fonts/bootstrap/glyphicons-halflings-regular.ttf", 32 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff", 33 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff2" 34 | ] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dist/angularjs-dropdown-multiselect.min.js: -------------------------------------------------------------------------------- 1 | /******/!function(e){function t(l){if(n[l])return n[l].exports;var o=n[l]={exports:{},id:l,loaded:!1};return e[l].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}// webpackBootstrap 2 | /******/ 3 | var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function l(e){return e&&e.__esModule?e:{"default":e}}var o=n(1),s=l(o);angular.module("angularjs-dropdown-multiselect",[]).directive("dmDropdownStaticInclude",["$compile",function(e){"ngInject";return function(t,n,l){var o=l.dmDropdownStaticInclude,s=n.html(o).contents();e(s)(t)}}]).directive("ngDropdownMultiselect",s["default"])},function(e,t,n){"use strict";function l(e){return e&&e.__esModule?e:{"default":e}}function o(){return{restrict:"AE",scope:{selectedModel:"=",options:"=",extraSettings:"=",events:"=",searchFilter:"=?",translationTexts:"=",disabled:"="},transclude:{toggleDropdown:"?toggleDropdown"},controller:i["default"],templateUrl:"app/component/angularjs-dropdown-multiselect.html"}}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=o;var s=n(2),i=l(s)},function(e,t){"use strict";function n(e,t){var n=!1;return e.some(function(e){return e===t?(n=!0,!0):!1}),n}function l(e,t,n){var l=-1;return e.some(function(e,o){return e[n]===t[n]?(l=o,!0):!1}),l}function o(e,t,o,s){"ngInject";function i(){setTimeout(function(){var e=angular.element(t)[0].querySelector(".option");angular.isDefined(e)&&null!=e&&e.focus()},0)}function r(){e.open?e.close():e.open=!0,e.settings.keyboardControls&&e.open&&(1===e.settings.selectionLimit&&e.settings.enableSearch?setTimeout(function(){angular.element(t)[0].querySelector(".searchField").focus()},0):i()),e.settings.enableSearch&&e.open&&setTimeout(function(){angular.element(t)[0].querySelector(".searchField").focus()},0)}function c(t,n){e.setSelectedItem(n,!1,!0),t.stopImmediatePropagation()}function a(){e.open=!1,e.input.searchFilter=e.settings.clearSearchOnClose?"":e.input.searchFilter,e.externalEvents.onClose()}function d(t){e.selectedModel.splice(0,e.selectedModel.length),e.options.forEach(function(n){n[e.settings.groupBy]===t&&e.setSelectedItem(n,!1,!1)}),e.externalEvents.onSelectionChanged()}function u(t){return null!==e.settings.groupByTextProvider?e.settings.groupByTextProvider(t):t}function g(e){var n=t.find("button"),l=document.createElement("canvas"),o=l.getContext("2d");return o.font=n.css("font-size")+n.css("font-family"),o.originalFont=n.css("font-size")+n.css("font-family"),o.fillStyle="#000000",o.measureText(e).width}function p(){if(e.settings.dynamicTitle&&e.selectedModel&&e.selectedModel.length>0){if(angular.isFunction(e.settings.smartButtonTextProvider))return e.settings.smartButtonTextProvider(e.selectedModel);if(e.settings.smartButtonMaxItems>0){var n=24,l=2,o=8,s=t[0].offsetWidth-n-l-o,i=[];angular.forEach(e.options,function(t){if(e.isChecked(t)){var n=e.getPropertyForObject(t,e.settings.displayProp),l=e.settings.smartButtonTextConverter(n,t);i.push(l||n)}}),e.selectedModel.length>e.settings.smartButtonMaxItems&&(i=i.slice(0,e.settings.smartButtonMaxItems),i.push("..."));var r=i.join(", "),c=r.length-4;if(0===t[0].offsetWidth)return r;if(s<=g("..."))return"...";for(;g(r)>s;)"..."!==i[i.length-1]&&(i.push("..."),r+="...",c=r.length-4),r=r.slice(0,c)+r.slice(c+1),c-=1;return r}var a=angular.isDefined(e.selectedModel)?e.selectedModel.length:0;return 0===a?e.texts.buttonDefaultText:e.settings.showAllSelectedText&&a===e.options.length?e.texts.allSelectedText:a+" "+e.texts.dynamicButtonTextSuffix}return e.texts.buttonDefaultText}function h(e,t){return angular.isDefined(e)&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0}function f(){e.deselectAll(!0),e.externalEvents.onSelectAll();var t=o("filter")(e.options,e.getFilter(e.input.searchFilter));angular.forEach(t,function(t){e.setSelectedItem(t,!0,!1)}),e.externalEvents.onSelectionChanged(),e.selectedGroup=null}function m(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:!1;t||e.externalEvents.onDeselectAll(),e.selectedModel.splice(0,e.selectedModel.length),t||e.externalEvents.onSelectionChanged(),e.selectedGroup=null}function y(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:!1,o=arguments[2],s=void 0,i=void 0;angular.isDefined(A.idProperty)?(s=-1!==l(e.selectedModel,t,A.idProperty),i=l(e.selectedModel,t,A.idProperty)):(s=-1!==e.selectedModel.indexOf(t),i=e.selectedModel.indexOf(t)),!n&&s?(e.selectedModel.splice(i,1),e.externalEvents.onItemDeselect(t),e.settings.closeOnDeselect&&e.close()):!s&&(0===e.settings.selectionLimit||e.selectedModel.length0&&e.selectedModel.length===e.settings.selectionLimit&&e.externalEvents.onMaxSelectionReached()):1!==e.settings.selectionLimit||s||e.selectedModel.length!==e.settings.selectionLimit||(e.selectedModel.splice(0,1),e.selectedModel.push(t),o&&e.externalEvents.onItemSelect(t),e.settings.closeOnSelect&&e.close()),o&&e.externalEvents.onSelectionChanged(),e.selectedGroup=null}function v(t){return angular.isDefined(A.idProperty)?-1!==l(e.selectedModel,t,A.idProperty):-1!==e.selectedModel.indexOf(t)}function k(t){var n=angular.element(t.target).scope(),l=void 0,o=t.target.parentNode;if(e.settings.keyboardControls)if(13===t.keyCode||32===t.keyCode)t.preventDefault(),n.option?e.setSelectedItem(n.option,!1,!0):"deselectAll"===t.target.id?e.deselectAll():"selectAll"===t.target.id&&e.selectAll();else if(38===t.keyCode){for(t.preventDefault(),o.previousElementSibling&&(l=o.previousElementSibling.querySelector("a")||o.previousElementSibling.querySelector("input"));!l&&o;)o=o.previousElementSibling,o&&(l=o.querySelector("a")||o.querySelector("input"));l&&l.focus()}else if(40===t.keyCode){for(t.preventDefault(),o.nextElementSibling&&(l=o.nextElementSibling.querySelector("a")||o.nextElementSibling.querySelector("input"));!l&&o;)o=o.nextElementSibling,o&&(l=o.querySelector("a")||o.querySelector("input"));l&&l.focus()}else 27===t.keyCode&&(t.preventDefault(),e.toggleDropdown())}function b(t){var n=t.target.parentNode.parentNode,l=void 0;if(e.settings.keyboardControls)if(9===t.keyCode||40===t.keyCode)t.preventDefault(),i();else if(38===t.keyCode){for(t.preventDefault(),n.previousElementSibling&&(l=n.previousElementSibling.querySelector("a")||n.previousElementSibling.querySelector("input"));!l&&n;)n=n.previousElementSibling,n&&(l=n.querySelector("a")||n.querySelector("input"));l&&l.focus()}else 27===t.keyCode&&(t.preventDefault(),e.toggleDropdown())}function x(t,n){var l=void 0;e.settings.keyboardControls&&13===t.keyCode&&(1===e.settings.selectionLimit&&e.settings.enableSearch?(l=o("filter")(e.options,e.getFilter(n)),1===l.length&&e.setSelectedItem(l[0],!1,!0)):e.settings.enableSearch&&e.selectAll())}function S(t){var n={};return n[e.settings.searchField]=t,n}function w(t){t&&t.stopPropagation(),e.settings.enableSearch=!e.settings.enableSearch,e.settings.enableSearch||(e.input.searchFilter="")}function C(){e.settings.keyboardControls&&13===event.keyCode&&(e.toggleSearch(),e.settings.enableSearch?setTimeout(function(){angular.element(t)[0].querySelector(".searchField").focus()},0):i())}function D(t,n){if(angular.isUndefined(n))return-1;if(angular.isUndefined(t))return 1;if("object"!==t.type||"object"!==n.type)return t.index
')}]); 4 | //# sourceMappingURL=maps/angularjs-dropdown-multiselect.min.js.map 5 | -------------------------------------------------------------------------------- /dist/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/dist/index.css -------------------------------------------------------------------------------- /dist/maps/angularjs-dropdown-multiselect.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["angularjs-dropdown-multiselect.min.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","_interopRequireDefault","obj","__esModule","default","_angularjsDropdownMultiselect","_angularjsDropdownMultiselect2","angular","directive","$compile","scope","element","attrs","template","dmDropdownStaticInclude","contents","html","dropdownMultiselectDirective","restrict","selectedModel","options","extraSettings","events","searchFilter","translationTexts","disabled","transclude","toggleDropdown","controller","templateUrl","Object","defineProperty","value","contains","collection","target","containsTarget","some","object","getIndexByProperty","objectToFind","property","index","option","ind","dropdownMultiselectController","$scope","$element","$filter","$document","focusFirstOption","setTimeout","elementToFocus","querySelector","isDefined","focus","open","close","settings","keyboardControls","selectionLimit","enableSearch","checkboxClick","$event","setSelectedItem","stopImmediatePropagation","input","clearSearchOnClose","externalEvents","onClose","selectCurrentGroup","currentGroup","splice","length","forEach","item","groupBy","onSelectionChanged","getGroupLabel","groupValue","groupByTextProvider","textWidth","text","$btn","find","canvas","document","createElement","ctx","getContext","font","css","originalFont","fillStyle","measureText","width","getButtonText","dynamicTitle","isFunction","smartButtonTextProvider","smartButtonMaxItems","paddingWidth","borderWidth","dropdownIconWidth","widthLimit","offsetWidth","itemsText","optionItem","isChecked","displayText","getPropertyForObject","displayProp","converterResponse","smartButtonTextConverter","push","slice","result","join","totalSelected","texts","buttonDefaultText","showAllSelectedText","allSelectedText","dynamicButtonTextSuffix","prototype","hasOwnProperty","undefined","selectAll","deselectAll","onSelectAll","searchResult","getFilter","selectedGroup","dontSendEvent","arguments","onDeselectAll","dontRemove","fireSelectionChange","exists","indexOfOption","idProperty","indexOf","onItemDeselect","closeOnDeselect","onItemSelect","closeOnSelect","onMaxSelectionReached","keyDownLink","event","sourceScope","nextOption","parent","parentNode","keyCode","preventDefault","previousElementSibling","nextElementSibling","keyDownSearchDefault","keyDownSearch","filter","searchField","toggleSearch","stopPropagation","keyDownToggleSearch","orderFunction","object1","object2","isUndefined","type","v1","v2","selectedToTop","$dropdownTrigger","children","noop","onInitDone","scrollable","scrollableHeight","closeOnBlur","showCheckAll","showUncheckAll","showEnableSearchButton","buttonClasses","checkBoxes","styleActive","checkAll","uncheckAll","selectionCount","selectionOf","searchPlaceholder","disableSearch","selectGroup","extend","on","e","parentElement","parentFound","className","split","$apply","$inject","run","$templateCache","put"],"mappings":"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","file":"angularjs-dropdown-multiselect.min.js","sourceRoot":"/source/","sourcesContent":[]} -------------------------------------------------------------------------------- /dist/src/angularjs-dropdown-multiselect.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports, __webpack_require__) { 46 | 47 | 'use strict'; 48 | 49 | var _angularjsDropdownMultiselect = __webpack_require__(1); 50 | 51 | var _angularjsDropdownMultiselect2 = _interopRequireDefault(_angularjsDropdownMultiselect); 52 | 53 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 54 | 55 | angular.module('angularjs-dropdown-multiselect', []).directive('dmDropdownStaticInclude', ["$compile", function ($compile) { 56 | 'ngInject'; 57 | 58 | return function directive(scope, element, attrs) { 59 | var template = attrs.dmDropdownStaticInclude; 60 | var contents = element.html(template).contents(); 61 | $compile(contents)(scope); 62 | }; 63 | }]).directive('ngDropdownMultiselect', _angularjsDropdownMultiselect2.default); 64 | 65 | /***/ }, 66 | /* 1 */ 67 | /***/ function(module, exports, __webpack_require__) { 68 | 69 | 'use strict'; 70 | 71 | Object.defineProperty(exports, "__esModule", { 72 | value: true 73 | }); 74 | exports.default = dropdownMultiselectDirective; 75 | 76 | var _angularjsDropdownMultiselect = __webpack_require__(2); 77 | 78 | var _angularjsDropdownMultiselect2 = _interopRequireDefault(_angularjsDropdownMultiselect); 79 | 80 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 81 | 82 | function dropdownMultiselectDirective() { 83 | return { 84 | restrict: 'AE', 85 | scope: { 86 | selectedModel: '=', 87 | options: '=', 88 | extraSettings: '=', 89 | events: '=', 90 | searchFilter: '=?', 91 | translationTexts: '=', 92 | disabled: '=' 93 | }, 94 | transclude: { 95 | toggleDropdown: '?toggleDropdown' 96 | }, 97 | controller: _angularjsDropdownMultiselect2.default, 98 | templateUrl: 'app/component/angularjs-dropdown-multiselect.html' 99 | }; 100 | } 101 | 102 | /***/ }, 103 | /* 2 */ 104 | /***/ function(module, exports) { 105 | 106 | 'use strict'; 107 | 108 | dropdownMultiselectController.$inject = ["$scope", "$element", "$filter", "$document"]; 109 | Object.defineProperty(exports, "__esModule", { 110 | value: true 111 | }); 112 | exports.default = dropdownMultiselectController; 113 | /* 114 | eslint no-param-reassign: [ 115 | "error", 116 | { 117 | "props": true, 118 | "ignorePropertyModificationsFor": [ 119 | "$scope" 120 | ] 121 | } 122 | ] 123 | */ 124 | 125 | function contains(collection, target) { 126 | var containsTarget = false; 127 | collection.some(function (object) { 128 | if (object === target) { 129 | containsTarget = true; 130 | return true; 131 | } 132 | return false; 133 | }); 134 | return containsTarget; 135 | } 136 | 137 | function getIndexByProperty(collection, objectToFind, property) { 138 | var index = -1; 139 | collection.some(function (option, ind) { 140 | if (option[property] === objectToFind[property]) { 141 | index = ind; 142 | return true; 143 | } 144 | return false; 145 | }); 146 | return index; 147 | } 148 | 149 | function dropdownMultiselectController($scope, $element, $filter, $document) { 150 | 'ngInject'; 151 | 152 | var $dropdownTrigger = $element.children()[0]; 153 | var externalEvents = { 154 | onItemSelect: angular.noop, 155 | onItemDeselect: angular.noop, 156 | onSelectAll: angular.noop, 157 | onDeselectAll: angular.noop, 158 | onInitDone: angular.noop, 159 | onMaxSelectionReached: angular.noop, 160 | onSelectionChanged: angular.noop, 161 | onClose: angular.noop 162 | }; 163 | 164 | var settings = { 165 | dynamicTitle: true, 166 | scrollable: false, 167 | scrollableHeight: '300px', 168 | closeOnBlur: true, 169 | displayProp: 'label', 170 | enableSearch: false, 171 | clearSearchOnClose: false, 172 | selectionLimit: 0, 173 | showCheckAll: true, 174 | showUncheckAll: true, 175 | showEnableSearchButton: false, 176 | closeOnSelect: false, 177 | buttonClasses: 'btn btn-default', 178 | closeOnDeselect: false, 179 | groupBy: undefined, 180 | checkBoxes: false, 181 | groupByTextProvider: null, 182 | smartButtonMaxItems: 0, 183 | smartButtonTextConverter: angular.noop, 184 | styleActive: false, 185 | selectedToTop: false, 186 | keyboardControls: false, 187 | template: '{{getPropertyForObject(option, settings.displayProp)}}', 188 | searchField: '$', 189 | showAllSelectedText: false 190 | }; 191 | 192 | var texts = { 193 | checkAll: 'Check All', 194 | uncheckAll: 'Uncheck All', 195 | selectionCount: 'checked', 196 | selectionOf: '/', 197 | searchPlaceholder: 'Search...', 198 | buttonDefaultText: 'Select', 199 | dynamicButtonTextSuffix: 'checked', 200 | disableSearch: 'Disable search', 201 | enableSearch: 'Enable search', 202 | selectGroup: 'Select all:', 203 | allSelectedText: 'All' 204 | }; 205 | 206 | var input = { 207 | searchFilter: $scope.searchFilter || '' 208 | }; 209 | 210 | angular.extend(settings, $scope.extraSettings || []); 211 | angular.extend(externalEvents, $scope.events || []); 212 | angular.extend(texts, $scope.translationTexts); 213 | 214 | if (settings.closeOnBlur) { 215 | $document.on('click', function (e) { 216 | if ($scope.open) { 217 | var target = e.target.parentElement; 218 | var parentFound = false; 219 | 220 | while (angular.isDefined(target) && target !== null && !parentFound) { 221 | if (!!target.className.split && contains(target.className.split(' '), 'multiselect-parent') && !parentFound) { 222 | if (target === $dropdownTrigger) { 223 | parentFound = true; 224 | } 225 | } 226 | target = target.parentElement; 227 | } 228 | 229 | if (!parentFound) { 230 | $scope.$apply(function () { 231 | $scope.close(); 232 | }); 233 | } 234 | } 235 | }); 236 | } 237 | 238 | angular.extend($scope, { 239 | toggleDropdown: toggleDropdown, 240 | checkboxClick: checkboxClick, 241 | externalEvents: externalEvents, 242 | settings: settings, 243 | texts: texts, 244 | input: input, 245 | close: close, 246 | selectCurrentGroup: selectCurrentGroup, 247 | getGroupLabel: getGroupLabel, 248 | getButtonText: getButtonText, 249 | getPropertyForObject: getPropertyForObject, 250 | selectAll: selectAll, 251 | deselectAll: deselectAll, 252 | setSelectedItem: setSelectedItem, 253 | isChecked: isChecked, 254 | keyDownLink: keyDownLink, 255 | keyDownSearchDefault: keyDownSearchDefault, 256 | keyDownSearch: keyDownSearch, 257 | getFilter: getFilter, 258 | toggleSearch: toggleSearch, 259 | keyDownToggleSearch: keyDownToggleSearch, 260 | orderFunction: orderFunction 261 | }); 262 | 263 | $scope.externalEvents.onInitDone(); 264 | 265 | function focusFirstOption() { 266 | setTimeout(function () { 267 | var elementToFocus = angular.element($element)[0].querySelector('.option'); 268 | if (angular.isDefined(elementToFocus) && elementToFocus != null) { 269 | elementToFocus.focus(); 270 | } 271 | }, 0); 272 | } 273 | 274 | function toggleDropdown() { 275 | if ($scope.open) { 276 | $scope.close(); 277 | } else { 278 | $scope.open = true; 279 | } 280 | if ($scope.settings.keyboardControls) { 281 | if ($scope.open) { 282 | if ($scope.settings.selectionLimit === 1 && $scope.settings.enableSearch) { 283 | setTimeout(function () { 284 | angular.element($element)[0].querySelector('.searchField').focus(); 285 | }, 0); 286 | } else { 287 | focusFirstOption(); 288 | } 289 | } 290 | } 291 | if ($scope.settings.enableSearch) { 292 | if ($scope.open) { 293 | setTimeout(function () { 294 | angular.element($element)[0].querySelector('.searchField').focus(); 295 | }, 0); 296 | } 297 | } 298 | } 299 | 300 | function checkboxClick($event, option) { 301 | $scope.setSelectedItem(option, false, true); 302 | $event.stopImmediatePropagation(); 303 | } 304 | 305 | function close() { 306 | $scope.open = false; 307 | $scope.input.searchFilter = $scope.settings.clearSearchOnClose ? '' : $scope.input.searchFilter; 308 | $scope.externalEvents.onClose(); 309 | } 310 | 311 | function selectCurrentGroup(currentGroup) { 312 | $scope.selectedModel.splice(0, $scope.selectedModel.length); 313 | $scope.options.forEach(function (item) { 314 | if (item[$scope.settings.groupBy] === currentGroup) { 315 | $scope.setSelectedItem(item, false, false); 316 | } 317 | }); 318 | $scope.externalEvents.onSelectionChanged(); 319 | } 320 | 321 | function getGroupLabel(groupValue) { 322 | if ($scope.settings.groupByTextProvider !== null) { 323 | return $scope.settings.groupByTextProvider(groupValue); 324 | } 325 | 326 | return groupValue; 327 | } 328 | 329 | function textWidth(text) { 330 | var $btn = $element.find('button'); 331 | var canvas = document.createElement('canvas'); 332 | var ctx = canvas.getContext('2d'); 333 | ctx.font = $btn.css('font-size') + $btn.css('font-family'); 334 | // http://stackoverflow.com/questions/38823353/chrome-canvas-2d-context-measuretext-giving-me-weird-results 335 | ctx.originalFont = $btn.css('font-size') + $btn.css('font-family'); 336 | ctx.fillStyle = '#000000'; 337 | return ctx.measureText(text).width; 338 | } 339 | 340 | function getButtonText() { 341 | if ($scope.settings.dynamicTitle && $scope.selectedModel && $scope.selectedModel.length > 0) { 342 | if (angular.isFunction($scope.settings.smartButtonTextProvider)) { 343 | return $scope.settings.smartButtonTextProvider($scope.selectedModel); 344 | } 345 | 346 | if ($scope.settings.smartButtonMaxItems > 0) { 347 | var paddingWidth = 12 * 2; 348 | var borderWidth = 1 * 2; 349 | var dropdownIconWidth = 8; 350 | var widthLimit = $element[0].offsetWidth - paddingWidth - borderWidth - dropdownIconWidth; 351 | 352 | var itemsText = []; 353 | 354 | angular.forEach($scope.options, function (optionItem) { 355 | if ($scope.isChecked(optionItem)) { 356 | var displayText = $scope.getPropertyForObject(optionItem, $scope.settings.displayProp); 357 | var converterResponse = $scope.settings.smartButtonTextConverter(displayText, optionItem); 358 | 359 | itemsText.push(converterResponse || displayText); 360 | } 361 | }); 362 | 363 | if ($scope.selectedModel.length > $scope.settings.smartButtonMaxItems) { 364 | itemsText = itemsText.slice(0, $scope.settings.smartButtonMaxItems); 365 | itemsText.push('...'); 366 | } 367 | 368 | var result = itemsText.join(', '); 369 | var index = result.length - 4; 370 | if ($element[0].offsetWidth === 0) { 371 | return result; 372 | } 373 | if (widthLimit <= textWidth('...')) { 374 | return '...'; 375 | } 376 | while (textWidth(result) > widthLimit) { 377 | if (itemsText[itemsText.length - 1] !== '...') { 378 | itemsText.push('...'); 379 | result = result + '...'; 380 | index = result.length - 4; 381 | } 382 | result = result.slice(0, index) + result.slice(index + 1); 383 | index -= 1; 384 | } 385 | 386 | return result; 387 | } 388 | var totalSelected = angular.isDefined($scope.selectedModel) ? $scope.selectedModel.length : 0; 389 | 390 | if (totalSelected === 0) { 391 | return $scope.texts.buttonDefaultText; 392 | } 393 | 394 | if ($scope.settings.showAllSelectedText && totalSelected === $scope.options.length) { 395 | return $scope.texts.allSelectedText; 396 | } 397 | 398 | return totalSelected + ' ' + $scope.texts.dynamicButtonTextSuffix; 399 | } 400 | return $scope.texts.buttonDefaultText; 401 | } 402 | 403 | function getPropertyForObject(object, property) { 404 | if (angular.isDefined(object) && Object.prototype.hasOwnProperty.call(object, property)) { 405 | return object[property]; 406 | } 407 | 408 | return undefined; 409 | } 410 | 411 | function selectAll() { 412 | $scope.deselectAll(true); 413 | $scope.externalEvents.onSelectAll(); 414 | 415 | var searchResult = $filter('filter')($scope.options, $scope.getFilter($scope.input.searchFilter)); 416 | angular.forEach(searchResult, function (value) { 417 | $scope.setSelectedItem(value, true, false); 418 | }); 419 | $scope.externalEvents.onSelectionChanged(); 420 | $scope.selectedGroup = null; 421 | } 422 | 423 | function deselectAll() { 424 | var dontSendEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; 425 | 426 | if (!dontSendEvent) { 427 | $scope.externalEvents.onDeselectAll(); 428 | } 429 | 430 | $scope.selectedModel.splice(0, $scope.selectedModel.length); 431 | if (!dontSendEvent) { 432 | $scope.externalEvents.onSelectionChanged(); 433 | } 434 | $scope.selectedGroup = null; 435 | } 436 | 437 | function setSelectedItem(option) { 438 | var dontRemove = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; 439 | var fireSelectionChange = arguments[2]; 440 | 441 | var exists = void 0; 442 | var indexOfOption = void 0; 443 | if (angular.isDefined(settings.idProperty)) { 444 | exists = getIndexByProperty($scope.selectedModel, option, settings.idProperty) !== -1; 445 | indexOfOption = getIndexByProperty($scope.selectedModel, option, settings.idProperty); 446 | } else { 447 | exists = $scope.selectedModel.indexOf(option) !== -1; 448 | indexOfOption = $scope.selectedModel.indexOf(option); 449 | } 450 | 451 | if (!dontRemove && exists) { 452 | $scope.selectedModel.splice(indexOfOption, 1); 453 | $scope.externalEvents.onItemDeselect(option); 454 | if ($scope.settings.closeOnDeselect) { 455 | $scope.close(); 456 | } 457 | } else if (!exists && ($scope.settings.selectionLimit === 0 || $scope.selectedModel.length < $scope.settings.selectionLimit)) { 458 | $scope.selectedModel.push(option); 459 | if (fireSelectionChange) { 460 | $scope.externalEvents.onItemSelect(option); 461 | } 462 | if ($scope.settings.closeOnSelect) { 463 | $scope.close(); 464 | } 465 | if ($scope.settings.selectionLimit > 0 && $scope.selectedModel.length === $scope.settings.selectionLimit) { 466 | $scope.externalEvents.onMaxSelectionReached(); 467 | } 468 | } else if ($scope.settings.selectionLimit === 1 && !exists && $scope.selectedModel.length === $scope.settings.selectionLimit) { 469 | $scope.selectedModel.splice(0, 1); 470 | $scope.selectedModel.push(option); 471 | if (fireSelectionChange) { 472 | $scope.externalEvents.onItemSelect(option); 473 | } 474 | if ($scope.settings.closeOnSelect) { 475 | $scope.close(); 476 | } 477 | } 478 | if (fireSelectionChange) { 479 | $scope.externalEvents.onSelectionChanged(); 480 | } 481 | $scope.selectedGroup = null; 482 | } 483 | 484 | function isChecked(option) { 485 | if (angular.isDefined(settings.idProperty)) { 486 | return getIndexByProperty($scope.selectedModel, option, settings.idProperty) !== -1; 487 | } 488 | return $scope.selectedModel.indexOf(option) !== -1; 489 | } 490 | 491 | function keyDownLink(event) { 492 | var sourceScope = angular.element(event.target).scope(); 493 | var nextOption = void 0; 494 | var parent = event.target.parentNode; 495 | if (!$scope.settings.keyboardControls) { 496 | return; 497 | } 498 | if (event.keyCode === 13 || event.keyCode === 32) { 499 | // enter 500 | event.preventDefault(); 501 | if (sourceScope.option) { 502 | $scope.setSelectedItem(sourceScope.option, false, true); 503 | } else if (event.target.id === 'deselectAll') { 504 | $scope.deselectAll(); 505 | } else if (event.target.id === 'selectAll') { 506 | $scope.selectAll(); 507 | } 508 | } else if (event.keyCode === 38) { 509 | // up arrow 510 | event.preventDefault(); 511 | if (parent.previousElementSibling) { 512 | nextOption = parent.previousElementSibling.querySelector('a') || parent.previousElementSibling.querySelector('input'); 513 | } 514 | while (!nextOption && !!parent) { 515 | parent = parent.previousElementSibling; 516 | if (parent) { 517 | nextOption = parent.querySelector('a') || parent.querySelector('input'); 518 | } 519 | } 520 | if (nextOption) { 521 | nextOption.focus(); 522 | } 523 | } else if (event.keyCode === 40) { 524 | // down arrow 525 | event.preventDefault(); 526 | if (parent.nextElementSibling) { 527 | nextOption = parent.nextElementSibling.querySelector('a') || parent.nextElementSibling.querySelector('input'); 528 | } 529 | while (!nextOption && !!parent) { 530 | parent = parent.nextElementSibling; 531 | if (parent) { 532 | nextOption = parent.querySelector('a') || parent.querySelector('input'); 533 | } 534 | } 535 | if (nextOption) { 536 | nextOption.focus(); 537 | } 538 | } else if (event.keyCode === 27) { 539 | event.preventDefault(); 540 | 541 | $scope.toggleDropdown(); 542 | } 543 | } 544 | 545 | function keyDownSearchDefault(event) { 546 | var parent = event.target.parentNode.parentNode; 547 | var nextOption = void 0; 548 | if (!$scope.settings.keyboardControls) { 549 | return; 550 | } 551 | if (event.keyCode === 9 || event.keyCode === 40) { 552 | // tab 553 | event.preventDefault(); 554 | focusFirstOption(); 555 | } else if (event.keyCode === 38) { 556 | event.preventDefault(); 557 | if (parent.previousElementSibling) { 558 | nextOption = parent.previousElementSibling.querySelector('a') || parent.previousElementSibling.querySelector('input'); 559 | } 560 | while (!nextOption && !!parent) { 561 | parent = parent.previousElementSibling; 562 | if (parent) { 563 | nextOption = parent.querySelector('a') || parent.querySelector('input'); 564 | } 565 | } 566 | if (nextOption) { 567 | nextOption.focus(); 568 | } 569 | } else if (event.keyCode === 27) { 570 | event.preventDefault(); 571 | 572 | $scope.toggleDropdown(); 573 | } 574 | } 575 | 576 | function keyDownSearch(event, searchFilter) { 577 | var searchResult = void 0; 578 | if (!$scope.settings.keyboardControls) { 579 | return; 580 | } 581 | if (event.keyCode === 13) { 582 | if ($scope.settings.selectionLimit === 1 && $scope.settings.enableSearch) { 583 | searchResult = $filter('filter')($scope.options, $scope.getFilter(searchFilter)); 584 | if (searchResult.length === 1) { 585 | $scope.setSelectedItem(searchResult[0], false, true); 586 | } 587 | } else if ($scope.settings.enableSearch) { 588 | $scope.selectAll(); 589 | } 590 | } 591 | } 592 | 593 | function getFilter(searchFilter) { 594 | var filter = {}; 595 | filter[$scope.settings.searchField] = searchFilter; 596 | return filter; 597 | } 598 | 599 | function toggleSearch($event) { 600 | if ($event) { 601 | $event.stopPropagation(); 602 | } 603 | $scope.settings.enableSearch = !$scope.settings.enableSearch; 604 | if (!$scope.settings.enableSearch) { 605 | $scope.input.searchFilter = ''; 606 | } 607 | } 608 | 609 | function keyDownToggleSearch() { 610 | if (!$scope.settings.keyboardControls) { 611 | return; 612 | } 613 | if (event.keyCode === 13) { 614 | $scope.toggleSearch(); 615 | if ($scope.settings.enableSearch) { 616 | setTimeout(function () { 617 | angular.element($element)[0].querySelector('.searchField').focus(); 618 | }, 0); 619 | } else { 620 | focusFirstOption(); 621 | } 622 | } 623 | } 624 | 625 | function orderFunction(object1, object2) { 626 | if (angular.isUndefined(object2)) { 627 | return -1; 628 | } 629 | if (angular.isUndefined(object1)) { 630 | return 1; 631 | } 632 | if (object1.type !== 'object' || object2.type !== 'object') { 633 | return object1.index < object2.index ? -1 : 1; 634 | } 635 | var v1 = object1.value; 636 | var v2 = object2.value; 637 | // first order by group 638 | if ($scope.settings.groupBy) { 639 | if (v1[$scope.settings.groupBy] !== v2[$scope.settings.groupBy]) { 640 | if (v1[$scope.settings.groupBy] < v2[$scope.settings.groupBy]) { 641 | return 1; 642 | } 643 | return -1; 644 | } 645 | } 646 | if (!$scope.settings.selectedToTop) { 647 | return $scope.options.indexOf(v1) < $scope.options.indexOf(v2) ? -1 : 1; 648 | } 649 | // then order selected to top 650 | if (!$scope.isChecked(v1) && !$scope.isChecked(v2) || $scope.isChecked(v1) && $scope.isChecked(v2)) { 651 | return $scope.options.indexOf(v1) < $scope.options.indexOf(v2) ? -1 : 1; 652 | } 653 | if ($scope.isChecked(v1)) { 654 | return -1; 655 | } 656 | return 1; 657 | } 658 | } 659 | 660 | /***/ } 661 | /******/ ]); 662 | angular.module("angularjs-dropdown-multiselect").run(["$templateCache", function($templateCache) {$templateCache.put("app/component/angularjs-dropdown-multiselect.html","
");}]); -------------------------------------------------------------------------------- /dist/src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/dist/src/index.css -------------------------------------------------------------------------------- /docs/assets/body-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/assets/body-bg.jpg -------------------------------------------------------------------------------- /docs/assets/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/assets/download-button.png -------------------------------------------------------------------------------- /docs/assets/github-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/assets/github-button.png -------------------------------------------------------------------------------- /docs/assets/header-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/assets/header-bg.jpg -------------------------------------------------------------------------------- /docs/assets/highlight-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/assets/highlight-bg.jpg -------------------------------------------------------------------------------- /docs/assets/sidebar-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/assets/sidebar-bg.jpg -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/docs/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | AngularJS Dropdown Multiselect
View project on
GitHub

AngularJS Dropdown Multiselect

based on Bootstrap's dropdown

-------------------------------------------------------------------------------- /docs/maps/scripts/app.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["scripts/app.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","_interopRequireDefault","obj","__esModule","default","_main","_main2","_v1docs","_v1docs2","angular","component","config","$stateProvider","$urlRouterProvider","state","name","url","template","otherwise","_angularjsDropdownMultiselect","_angularjsDropdownMultiselect2","directive","$compile","scope","element","attrs","dmDropdownStaticInclude","contents","html","dropdownMultiselectDirective","restrict","selectedModel","options","extraSettings","events","searchFilter","translationTexts","disabled","transclude","toggleDropdown","controller","templateUrl","Object","defineProperty","value","contains","collection","target","containsTarget","some","object","getIndexByProperty","objectToFind","property","index","option","ind","dropdownMultiselectController","$scope","$element","$filter","$document","focusFirstOption","setTimeout","elementToFocus","querySelector","isDefined","focus","open","close","settings","keyboardControls","selectionLimit","enableSearch","checkboxClick","$event","setSelectedItem","stopImmediatePropagation","input","clearSearchOnClose","externalEvents","onClose","selectCurrentGroup","currentGroup","splice","length","forEach","item","groupBy","onSelectionChanged","getGroupLabel","groupValue","groupByTextProvider","textWidth","text","$btn","find","canvas","document","createElement","ctx","getContext","font","css","originalFont","fillStyle","measureText","width","getButtonText","dynamicTitle","isFunction","smartButtonTextProvider","smartButtonMaxItems","paddingWidth","borderWidth","dropdownIconWidth","widthLimit","offsetWidth","itemsText","optionItem","isChecked","displayText","getPropertyForObject","displayProp","converterResponse","smartButtonTextConverter","push","slice","result","join","totalSelected","texts","buttonDefaultText","showAllSelectedText","allSelectedText","dynamicButtonTextSuffix","prototype","hasOwnProperty","undefined","selectAll","deselectAll","onSelectAll","searchResult","getFilter","selectedGroup","dontSendEvent","arguments","onDeselectAll","dontRemove","fireSelectionChange","exists","indexOfOption","idProperty","indexOf","onItemDeselect","closeOnDeselect","onItemSelect","closeOnSelect","onMaxSelectionReached","keyDownLink","event","sourceScope","nextOption","parent","parentNode","keyCode","preventDefault","previousElementSibling","nextElementSibling","keyDownSearchDefault","keyDownSearch","filter","searchField","toggleSearch","stopPropagation","keyDownToggleSearch","orderFunction","object1","object2","isUndefined","type","v1","v2","selectedToTop","$dropdownTrigger","children","noop","onInitDone","scrollable","scrollableHeight","closeOnBlur","showCheckAll","showUncheckAll","showEnableSearchButton","buttonClasses","checkBoxes","styleActive","checkAll","uncheckAll","selectionCount","selectionOf","searchPlaceholder","disableSearch","selectGroup","extend","on","e","parentElement","parentFound","className","split","$apply","$inject","mainComponent","_classCallCheck","instance","Constructor","TypeError","MainController","$log","this","testing","testmodel","testdata","label","testsettings","testevents","debug","example1model","example1data","example2model","example2data","example2settings","example5model","example5data","example5settings","example5customTexts","example6data","example6model","example6settings","example7model","example7data","example7settings","externalIdProp","customFilter","example8model","example8data","example8settings","example9model","example9data","example9settings","example10model","example10data","example10settings","example12model","example12data","example12settings","example11model","example11data","gender","example11settings","selectByGroupModel","selectByGroupData","selectByGroupSettings","selectByGroups","example13model","example13data","example13settings","itemText","example14model","example14data","example14settings","example15model","example15data","example15settings","example16model","example16data","example16settings","example17model","example17data","example17settings","example18model","example18data","example18settings","example19model","example19data","example19settings","example20model","example20data","age","example20settings","example21model","example21data","example21settings","searchSelectAllModel","searchSelectAllData","searchSelectAllSettings","disabledModel","disabledData","selectedToTopModel","selectedToTopData","selectedToTopSettings","stringModel","stringData","stringSettings","skip","transclusionModel","transclusionData","transclusionSettings","idPropertyModel","idPropertyData","idPropertySettings","smartButtonTextProviderModel","smartButtonTextProviderData","smartButtonTextProviderSettings","selectionArray","v1Component","run","$templateCache","put"],"mappings":"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","file":"scripts/app.js","sourceRoot":"/source/","sourcesContent":[]} -------------------------------------------------------------------------------- /gulp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var runSequence = require('run-sequence'); 6 | var concat = require('gulp-concat'); 7 | var conf = require('./conf'); 8 | 9 | var $ = require('gulp-load-plugins')({ 10 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 11 | }); 12 | 13 | gulp.task('partials', function() { 14 | return gulp.src([ 15 | path.join(conf.paths.src, conf.paths.template), 16 | path.join(conf.paths.tmp, '/serve/app/**/*.html') 17 | ]) 18 | .pipe($.htmlmin({ 19 | removeEmptyAttributes: true, 20 | removeAttributeQuotes: true, 21 | collapseBooleanAttributes: true, 22 | collapseWhitespace: true 23 | })) 24 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 25 | module: conf.names.module, 26 | root: conf.paths.templateRoot, 27 | })) 28 | .pipe(gulp.dest(conf.paths.tmp + '/partials/')); 29 | }); 30 | 31 | gulp.task('html', ['inject', 'partials'], function() { 32 | var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false }); 33 | var partialsInjectOptions = { 34 | starttag: '', 35 | ignorePath: path.join(conf.paths.tmp, '/partials'), 36 | addRootSlash: false 37 | }; 38 | 39 | var htmlFilter = $.filter('*.html', { restore: true }); 40 | var jsFilter = $.filter('**/*.js', { restore: true }); 41 | var cssFilter = $.filter('**/*.css', { restore: true }); 42 | 43 | return gulp.src(path.join(conf.paths.tmp, '/serve/*.html')) 44 | .pipe($.inject(partialsInjectFile, partialsInjectOptions)) 45 | .pipe($.useref()) 46 | .pipe(jsFilter) 47 | .pipe($.sourcemaps.init()) 48 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) 49 | .pipe($.sourcemaps.write('maps')) 50 | .pipe(jsFilter.restore) 51 | .pipe(cssFilter) 52 | // .pipe($.sourcemaps.init()) 53 | .pipe($.replace('../../bower_components/bootstrap-sass/assets/fonts/bootstrap/', '../fonts/')) 54 | .pipe($.cssnano()) 55 | // .pipe($.sourcemaps.write('maps')) 56 | .pipe(cssFilter.restore) 57 | .pipe(htmlFilter) 58 | .pipe($.htmlmin({ 59 | removeEmptyAttributes: true, 60 | removeAttributeQuotes: true, 61 | collapseBooleanAttributes: true, 62 | collapseWhitespace: true 63 | })) 64 | .pipe(htmlFilter.restore) 65 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))) 66 | .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true })); 67 | }); 68 | 69 | // Only applies for fonts from bower dependencies 70 | // Custom fonts are handled by the "other" task 71 | gulp.task('fonts', function() { 72 | return gulp.src($.mainBowerFiles({ 73 | paths: { 74 | bowerJson: 'bowerDocs.json' 75 | } 76 | })) 77 | .pipe($.filter('**/*.{eot,otf,svg,ttf,woff,woff2}')) 78 | .pipe($.flatten()) 79 | .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/'))); 80 | }); 81 | 82 | gulp.task('other', function() { 83 | var fileFilter = $.filter(function(file) { 84 | return file.stat.isFile(); 85 | }); 86 | 87 | return gulp.src([ 88 | path.join(conf.paths.src, '/**/*'), 89 | path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}') 90 | ]) 91 | .pipe(fileFilter) 92 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))); 93 | }); 94 | 95 | gulp.task('clean', function() { 96 | return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]); 97 | }); 98 | 99 | gulp.task('build', ['html', 'fonts', 'other']); 100 | 101 | gulp.task('conf:component', function(cb) { 102 | conf.paths.src = 'src/app/component'; 103 | conf.paths.dist = 'dist'; 104 | conf.paths.template = '**/*.html'; 105 | conf.paths.index = 'angularjs-dropdown-multiselect.module.js'; 106 | conf.paths.templateRoot = 'app/component/'; 107 | conf.paths.cssRoot = ''; 108 | conf.paths.bowerJson = '../bower.json'; 109 | conf.names.module = 'angularjs-dropdown-multiselect'; 110 | conf.wiredep.bowerJson = require(conf.paths.bowerJson); 111 | cb(); 112 | }); 113 | 114 | gulp.task('clean:component', ['conf:component'], function() { 115 | return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]); 116 | }); 117 | 118 | gulp.task('compile:component', ['clean:component'], function(cb) { 119 | runSequence(['scripts', 'styles', 'partials'], cb); 120 | }); 121 | 122 | gulp.task('build.component.minified', ['compile:component'], function () { 123 | var jsFilter = $.filter('**/*.js', { restore: true }); 124 | var cssFilter = $.filter('**/*.css', { restore: true }); 125 | 126 | return gulp.src([ 127 | path.join(conf.paths.tmp, 'serve/app/index.css'), 128 | path.join(conf.paths.tmp, 'serve/app/index.module.js'), 129 | path.join(conf.paths.tmp, 'partials/templateCacheHtml.js') 130 | ]) 131 | .pipe(jsFilter) 132 | .pipe(concat({ path: 'angularjs-dropdown-multiselect.min.js' })) 133 | .pipe($.sourcemaps.init()) 134 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) 135 | .pipe($.sourcemaps.write('maps')) 136 | .pipe(jsFilter.restore) 137 | .pipe(cssFilter) 138 | .pipe($.cssnano()) 139 | .pipe(cssFilter.restore) 140 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))) 141 | .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true })); 142 | }); 143 | 144 | gulp.task('build.component', ['compile:component'], function () { 145 | var jsFilter = $.filter('**/*.js', { restore: true }); 146 | var cssFilter = $.filter('**/*.css', { restore: true }); 147 | 148 | return gulp.src([ 149 | path.join(conf.paths.tmp, 'serve/app/index.css'), 150 | path.join(conf.paths.tmp, 'serve/app/index.module.js'), 151 | path.join(conf.paths.tmp, 'partials/templateCacheHtml.js') 152 | ]) 153 | .pipe(jsFilter) 154 | .pipe(concat({ path: 'angularjs-dropdown-multiselect.js' })) 155 | .pipe(jsFilter.restore) 156 | .pipe(cssFilter) 157 | .pipe($.cssnano()) 158 | .pipe(cssFilter.restore) 159 | .pipe(gulp.dest(path.join(conf.paths.dist, '/src'))) 160 | .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true })); 161 | }); 162 | 163 | gulp.task('build:component', ['build.component.minified', 'build.component']); 164 | -------------------------------------------------------------------------------- /gulp/conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains the variables used in other gulp files 3 | * which defines tasks 4 | * By design, we only put there very generic config values 5 | * which are used in several places to keep good readability 6 | * of the tasks 7 | */ 8 | 9 | var gutil = require('gulp-util'); 10 | 11 | /** 12 | * The main paths of your project handle these with care 13 | */ 14 | exports.paths = { 15 | src: 'src', 16 | dist: 'docs', 17 | tmp: '.tmp', 18 | e2e: 'e2e', 19 | template: '/app/**/*.html', 20 | index: '/app/index.module.js', 21 | templateRoot: 'app/', 22 | cssRoot: 'app/', 23 | bowerJson: '../bowerDocs.json', 24 | }; 25 | 26 | exports.names = { 27 | module: 'AngularjsDropdownMultiselectExample', 28 | } 29 | 30 | /** 31 | * Wiredep is the lib which inject bower dependencies in your project 32 | * Mainly used to inject script tags in the index.html but also used 33 | * to inject css preprocessor deps and js files in karma 34 | */ 35 | exports.wiredep = { 36 | exclude: [/\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/], 37 | directory: 'bower_components', 38 | bowerJson: require('../bowerDocs.json'), 39 | }; 40 | 41 | /** 42 | * Common implementation for an error handler of a Gulp plugin 43 | */ 44 | exports.errorHandler = function(title) { 45 | 'use strict'; 46 | 47 | return function(err) { 48 | gutil.log(gutil.colors.red('[' + title + ']'), err.toString()); 49 | this.emit('end'); 50 | }; 51 | }; 52 | -------------------------------------------------------------------------------- /gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | var wiredep = require('wiredep').stream; 10 | var _ = require('lodash'); 11 | 12 | var browserSync = require('browser-sync'); 13 | 14 | gulp.task('inject-reload', ['inject'], function() { 15 | browserSync.reload(); 16 | }); 17 | 18 | gulp.task('inject', ['scripts', 'styles'], function () { 19 | var injectStyles = gulp.src([ 20 | path.join(conf.paths.tmp, '/serve/app/**/*.css'), 21 | path.join('!' + conf.paths.tmp, '/serve/app/vendor.css') 22 | ], { read: false }); 23 | 24 | var injectScripts = gulp.src([ 25 | path.join(conf.paths.tmp, '/serve/app/**/*.module.js') 26 | ], { read: false }); 27 | 28 | var injectOptions = { 29 | ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')], 30 | addRootSlash: false 31 | }; 32 | 33 | return gulp.src(path.join(conf.paths.src, '/*.html')) 34 | .pipe($.inject(injectStyles, injectOptions)) 35 | .pipe($.inject(injectScripts, injectOptions)) 36 | .pipe(wiredep(_.extend({}, conf.wiredep))) 37 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve'))); 38 | }); 39 | -------------------------------------------------------------------------------- /gulp/scripts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | var webpack = require('webpack-stream'); 9 | 10 | var $ = require('gulp-load-plugins')(); 11 | 12 | 13 | function webpackWrapper(watch, test, callback) { 14 | var webpackOptions = { 15 | watch: watch, 16 | module: { 17 | preLoaders: [{ test: /\.js$/, exclude: /node_modules/, loader: 'eslint-loader'}], 18 | loaders: [{ test: /\.js$/, exclude: /node_modules/, loaders: ['ng-annotate', 'babel-loader?presets[]=es2015']}] 19 | }, 20 | output: { filename: 'index.module.js' } 21 | }; 22 | 23 | if(watch) { 24 | webpackOptions.devtool = 'inline-source-map'; 25 | } 26 | 27 | var webpackChangeHandler = function(err, stats) { 28 | if(err) { 29 | conf.errorHandler('Webpack')(err); 30 | } 31 | $.util.log(stats.toString({ 32 | colors: $.util.colors.supportsColor, 33 | chunks: false, 34 | hash: false, 35 | version: false 36 | })); 37 | browserSync.reload(); 38 | if(watch) { 39 | watch = false; 40 | callback(); 41 | } 42 | }; 43 | 44 | var sources = [path.join(conf.paths.src, conf.paths.index)]; 45 | if (test) { 46 | sources.push(path.join(conf.paths.src, '/app/**/*.spec.js')); 47 | } 48 | 49 | return gulp.src(sources) 50 | .pipe(webpack(webpackOptions, null, webpackChangeHandler)) 51 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app'))); 52 | } 53 | 54 | gulp.task('scripts', function () { 55 | return webpackWrapper(false, false); 56 | }); 57 | 58 | gulp.task('scripts:watch', ['scripts'], function (callback) { 59 | return webpackWrapper(true, false, callback); 60 | }); 61 | 62 | gulp.task('scripts:test', function () { 63 | return webpackWrapper(false, true); 64 | }); 65 | 66 | gulp.task('scripts:test-watch', ['scripts'], function (callback) { 67 | return webpackWrapper(true, true, callback); 68 | }); 69 | -------------------------------------------------------------------------------- /gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | var browserSyncSpa = require('browser-sync-spa'); 9 | 10 | var util = require('util'); 11 | 12 | var proxyMiddleware = require('http-proxy-middleware'); 13 | 14 | function browserSyncInit(baseDir, browser) { 15 | browser = browser === undefined ? 'default' : browser; 16 | 17 | var routes = null; 18 | if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) { 19 | routes = { 20 | '/bower_components': 'bower_components' 21 | }; 22 | } 23 | 24 | var server = { 25 | baseDir: baseDir, 26 | routes: routes 27 | }; 28 | 29 | /* 30 | * You can add a proxy to your backend by uncommenting the line below. 31 | * You just have to configure a context which will we redirected and the target url. 32 | * Example: $http.get('/users') requests will be automatically proxified. 33 | * 34 | * For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.9.0/README.md 35 | */ 36 | // server.middleware = proxyMiddleware('/users', {target: 'http://jsonplaceholder.typicode.com', changeOrigin: true}); 37 | 38 | browserSync.instance = browserSync.init({ 39 | startPath: '/', 40 | server: server, 41 | browser: browser 42 | }); 43 | } 44 | 45 | browserSync.use(browserSyncSpa({ 46 | selector: '[ng-app]'// Only needed for angular apps 47 | })); 48 | 49 | gulp.task('serve', ['watch'], function () { 50 | browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]); 51 | }); 52 | 53 | gulp.task('serve:dist', ['build'], function () { 54 | browserSyncInit(conf.paths.dist); 55 | }); 56 | 57 | gulp.task('serve:e2e', ['inject'], function () { 58 | browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []); 59 | }); 60 | 61 | gulp.task('serve:e2e-dist', ['build'], function () { 62 | browserSyncInit(conf.paths.dist, []); 63 | }); 64 | -------------------------------------------------------------------------------- /gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | var wiredep = require('wiredep').stream; 12 | var _ = require('lodash'); 13 | 14 | gulp.task('styles-reload', ['styles'], function() { 15 | return buildStyles() 16 | .pipe(browserSync.stream()); 17 | }); 18 | 19 | gulp.task('styles', function() { 20 | return buildStyles(); 21 | }); 22 | 23 | var buildStyles = function() { 24 | var sassOptions = { 25 | outputStyle: 'expanded', 26 | precision: 10 27 | }; 28 | 29 | var injectFiles = gulp.src([ 30 | path.join(conf.paths.src, conf.paths.cssRoot + '**/*.scss'), 31 | path.join('!' + conf.paths.src, '/app/index.scss'), 32 | path.join('!' + conf.paths.src, '/app/component/index.scss'), 33 | ], { read: false }); 34 | 35 | var injectOptions = { 36 | transform: function(filePath) { 37 | filePath = filePath.replace(conf.paths.src + '/' + conf.paths.cssRoot, ''); 38 | return '@import "' + filePath + '";'; 39 | }, 40 | starttag: '// injector', 41 | endtag: '// endinjector', 42 | addRootSlash: false 43 | }; 44 | 45 | return gulp.src([ 46 | path.join(conf.paths.src, conf.paths.cssRoot + '/index.scss') 47 | ]) 48 | .pipe($.inject(injectFiles, injectOptions)) 49 | .pipe(wiredep(_.extend({}, conf.wiredep))) 50 | .pipe($.sourcemaps.init()) 51 | .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass')) 52 | .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer')) 53 | .pipe($.sourcemaps.write()) 54 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); 55 | }; 56 | -------------------------------------------------------------------------------- /gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var karma = require('karma'); 8 | 9 | var pathSrcHtml = [ 10 | path.join(conf.paths.src, '/**/*.html') 11 | ]; 12 | 13 | var pathSrcJs = [ 14 | path.join(conf.paths.tmp, '/serve/app/index.module.js') 15 | ]; 16 | 17 | function runTests (singleRun, done) { 18 | var reporters = ['progress']; 19 | var preprocessors = {}; 20 | 21 | pathSrcHtml.forEach(function(path) { 22 | preprocessors[path] = ['ng-html2js']; 23 | }); 24 | 25 | if (singleRun) { 26 | pathSrcJs.forEach(function(path) { 27 | preprocessors[path] = ['coverage']; 28 | }); 29 | reporters.push('coverage') 30 | } 31 | 32 | var localConfig = { 33 | configFile: path.join(__dirname, '/../karma.conf.js'), 34 | singleRun: singleRun, 35 | autoWatch: !singleRun, 36 | reporters: reporters, 37 | preprocessors: preprocessors 38 | }; 39 | 40 | var server = new karma.Server(localConfig, function(failCount) { 41 | done(failCount ? new Error("Failed " + failCount + " tests.") : null); 42 | }) 43 | server.start(); 44 | } 45 | 46 | gulp.task('test', ['scripts:test'], function(done) { 47 | runTests(true, done); 48 | }); 49 | 50 | gulp.task('test:auto', ['scripts:test-watch'], function(done) { 51 | runTests(false, done); 52 | }); 53 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | function isOnlyChange(event) { 10 | return event.type === 'changed'; 11 | } 12 | 13 | gulp.task('watch', ['scripts:watch', 'inject'], function () { 14 | 15 | gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject-reload']); 16 | 17 | gulp.watch([ 18 | path.join(conf.paths.src, '/app/**/*.css'), 19 | path.join(conf.paths.src, '/app/**/*.scss') 20 | ], function(event) { 21 | if(isOnlyChange(event)) { 22 | gulp.start('styles-reload'); 23 | } else { 24 | gulp.start('inject-reload'); 25 | } 26 | }); 27 | 28 | 29 | gulp.watch(path.join(conf.paths.src, '/app/**/*.html'), function(event) { 30 | browserSync.reload(event.path); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your gulpfile! 3 | * The gulp tasks are split into several files in the gulp directory 4 | * because putting it all here was too long 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var fs = require('fs'); 10 | var gulp = require('gulp'); 11 | 12 | /** 13 | * This will load all js or coffee files in the gulp directory 14 | * in order to load all gulp tasks 15 | */ 16 | fs.readdirSync('./gulp').filter(function(file) { 17 | return (/\.(js|coffee)$/i).test(file); 18 | }).map(function(file) { 19 | require('./gulp/' + file); 20 | }); 21 | 22 | 23 | /** 24 | * Default task clean temporaries directories and launch the 25 | * main optimization build task 26 | */ 27 | gulp.task('default', ['clean'], function () { 28 | gulp.start('build'); 29 | }); 30 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var conf = require('./gulp/conf'); 5 | 6 | var _ = require('lodash'); 7 | var wiredep = require('wiredep'); 8 | 9 | var pathSrcHtml = [ 10 | path.join(conf.paths.src, '/**/*.html') 11 | ]; 12 | 13 | function listFiles() { 14 | var wiredepOptions = _.extend({}, conf.wiredep, { 15 | dependencies: true, 16 | devDependencies: true 17 | }); 18 | 19 | var patterns = wiredep(wiredepOptions).js 20 | .concat([ 21 | path.join(conf.paths.tmp, '/serve/app/index.module.js'), 22 | ]) 23 | .concat(pathSrcHtml); 24 | 25 | var files = patterns.map(function(pattern) { 26 | return { 27 | pattern: pattern 28 | }; 29 | }); 30 | files.push({ 31 | pattern: path.join(conf.paths.src, '/assets/**/*'), 32 | included: false, 33 | served: true, 34 | watched: false 35 | }); 36 | files.unshift('node_modules/babel-polyfill/dist/polyfill.js'); 37 | return files; 38 | } 39 | 40 | module.exports = function(config) { 41 | 42 | var configuration = { 43 | files: listFiles(), 44 | 45 | singleRun: true, 46 | 47 | autoWatch: false, 48 | 49 | ngHtml2JsPreprocessor: { 50 | stripPrefix: conf.paths.src + '/', 51 | moduleName: 'mf.DashboardDataDisplaying' 52 | }, 53 | 54 | logLevel: 'WARN', 55 | 56 | frameworks: ['phantomjs-shim', 'jasmine'], 57 | 58 | browsers : ['PhantomJS'], 59 | 60 | plugins : [ 61 | 'karma-phantomjs-launcher', 62 | 'karma-phantomjs-shim', 63 | 'karma-coverage', 64 | 'karma-jasmine', 65 | 'karma-ng-html2js-preprocessor' 66 | ], 67 | 68 | coverageReporter: { 69 | type : 'html', 70 | dir : 'coverage/' 71 | }, 72 | 73 | reporters: ['progress'], 74 | 75 | proxies: { 76 | '/assets/': path.join('/base/', conf.paths.src, '/assets/') 77 | }, 78 | 79 | failOnEmptyTestSuite: false 80 | }; 81 | 82 | // This is the default preprocessors configuration for a usage with Karma cli 83 | // The coverage preprocessor is added in gulp/unit-test.js only for single tests 84 | // It was not possible to do it there because karma doesn't let us now if we are 85 | // running a single test or not 86 | configuration.preprocessors = {}; 87 | pathSrcHtml.forEach(function(path) { 88 | configuration.preprocessors[path] = ['ng-html2js']; 89 | }); 90 | 91 | // This block is needed to execute Chrome on Travis 92 | // If you ever plan to use Chrome and Travis, you can keep it 93 | // If not, you can safely remove it 94 | // https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076 95 | if(configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) { 96 | configuration.customLaunchers = { 97 | 'chrome-travis-ci': { 98 | base: 'Chrome', 99 | flags: ['--no-sandbox'] 100 | } 101 | }; 102 | configuration.browsers = ['chrome-travis-ci']; 103 | } 104 | 105 | config.set(configuration); 106 | }; 107 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "pkempenaers@myforce.be", 3 | "name": "angularjs-dropdown-multiselect", 4 | "version": "2.0.0-beta.10", 5 | "description": "This directive gives you a Bootstrap Dropdown with the power of AngularJS directives.", 6 | "homepage": "http://dotansimha.github.io/angularjs-dropdown-multiselect/#/", 7 | "dependencies": { 8 | "angular": "~1" 9 | }, 10 | "devDependencies": { 11 | "babel-core": "~6.7.4", 12 | "babel-loader": "~6.2.4", 13 | "babel-preset-es2015": "~6.6.0", 14 | "browser-sync": "~2.9.11", 15 | "browser-sync-spa": "~1.0.3", 16 | "chalk": "~1.1.1", 17 | "del": "~2.0.2", 18 | "eslint": "~3.17.1", 19 | "eslint-config-airbnb": "~14.1.0", 20 | "eslint-loader": "~1.6.1", 21 | "eslint-plugin-angular": "~1.5.1", 22 | "eslint-plugin-import": "~2.2.0", 23 | "eslint-plugin-jsx-a11y": "~3.0.2", 24 | "eslint-plugin-react": "~6.9.0", 25 | "estraverse": "~4.1.0", 26 | "gulp": "~3.9.0", 27 | "gulp-angular-templatecache": "~1.8.0", 28 | "gulp-autoprefixer": "~3.0.2", 29 | "gulp-concat": "^2.6.1", 30 | "gulp-cssnano": "~2.1.1", 31 | "gulp-eslint": "~3.0.1", 32 | "gulp-filter": "~3.0.1", 33 | "gulp-flatten": "~0.2.0", 34 | "gulp-htmlmin": "~1.3.0", 35 | "gulp-inject": "~3.0.0", 36 | "gulp-load-plugins": "~0.10.0", 37 | "gulp-protractor": "~2.1.0", 38 | "gulp-rename": "~1.2.2", 39 | "gulp-replace": "~0.5.4", 40 | "gulp-sass": "~2.0.4", 41 | "gulp-size": "~2.0.0", 42 | "gulp-sourcemaps": "~1.6.0", 43 | "gulp-uglify": "~1.4.1", 44 | "gulp-useref": "~3.0.3", 45 | "gulp-util": "~3.0.6", 46 | "http-proxy-middleware": "~0.9.0", 47 | "karma": "~1.5.0", 48 | "karma-coverage": "~1.1.1", 49 | "karma-jasmine": "~1.1.0", 50 | "karma-ng-html2js-preprocessor": "~0.2.0", 51 | "karma-phantomjs-launcher": "~1.0.2", 52 | "karma-phantomjs-shim": "~1.4.0", 53 | "lodash": "~3.10.1", 54 | "main-bower-files": "~2.9.0", 55 | "ng-annotate-loader": "0.0.10", 56 | "phantomjs": "~2.1.7", 57 | "run-sequence": "^1.2.2", 58 | "uglify-save-license": "~0.4.1", 59 | "webpack-stream": "~2.1.1", 60 | "wiredep": "~2.2.2" 61 | }, 62 | "scripts": { 63 | "test": "echo \"Error: no test specified\" && exit 1" 64 | }, 65 | "repository": { 66 | "type": "git", 67 | "url": "git+https://github.com/dotansimha/angularjs-dropdown-multiselect.git" 68 | }, 69 | "engines": { 70 | "node": ">=0.10.10" 71 | }, 72 | "main": "dist/angularjs-dropdown-multiselect.min.js", 73 | "keywords": [ 74 | "angular", 75 | "multiselect" 76 | ], 77 | "license": "MIT", 78 | "bugs": { 79 | "url": "https://github.com/dotansimha/angularjs-dropdown-multiselect/issues" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/app/component/angularjs-dropdown-multiselect.controller.js: -------------------------------------------------------------------------------- 1 | /* 2 | eslint no-param-reassign: [ 3 | "error", 4 | { 5 | "props": true, 6 | "ignorePropertyModificationsFor": [ 7 | "$scope" 8 | ] 9 | } 10 | ] 11 | */ 12 | 13 | function contains(collection, target) { 14 | let containsTarget = false; 15 | collection.some((object) => { 16 | if (object === target) { 17 | containsTarget = true; 18 | return true; 19 | } 20 | return false; 21 | }); 22 | return containsTarget; 23 | } 24 | 25 | function getIndexByProperty(collection, objectToFind, property) { 26 | let index = -1; 27 | collection.some((option, ind) => { 28 | if (option[property] === objectToFind[property]) { 29 | index = ind; 30 | return true; 31 | } 32 | return false; 33 | }); 34 | return index; 35 | } 36 | 37 | export default function dropdownMultiselectController( 38 | $scope, 39 | $element, 40 | $filter, 41 | $document, 42 | ) { 43 | 'ngInject'; 44 | 45 | const $dropdownTrigger = $element.children()[0]; 46 | const externalEvents = { 47 | onItemSelect: angular.noop, 48 | onItemDeselect: angular.noop, 49 | onSelectAll: angular.noop, 50 | onDeselectAll: angular.noop, 51 | onInitDone: angular.noop, 52 | onMaxSelectionReached: angular.noop, 53 | onSelectionChanged: angular.noop, 54 | onClose: angular.noop, 55 | }; 56 | 57 | const settings = { 58 | dynamicTitle: true, 59 | scrollable: false, 60 | scrollableHeight: '300px', 61 | closeOnBlur: true, 62 | displayProp: 'label', 63 | enableSearch: false, 64 | clearSearchOnClose: false, 65 | selectionLimit: 0, 66 | showCheckAll: true, 67 | showUncheckAll: true, 68 | showEnableSearchButton: false, 69 | closeOnSelect: false, 70 | buttonClasses: 'btn btn-default', 71 | closeOnDeselect: false, 72 | groupBy: undefined, 73 | checkBoxes: false, 74 | groupByTextProvider: null, 75 | smartButtonMaxItems: 0, 76 | smartButtonTextConverter: angular.noop, 77 | styleActive: false, 78 | selectedToTop: false, 79 | keyboardControls: false, 80 | template: '{{getPropertyForObject(option, settings.displayProp)}}', 81 | searchField: '$', 82 | showAllSelectedText: false, 83 | }; 84 | 85 | const texts = { 86 | checkAll: 'Check All', 87 | uncheckAll: 'Uncheck All', 88 | selectionCount: 'checked', 89 | selectionOf: '/', 90 | searchPlaceholder: 'Search...', 91 | buttonDefaultText: 'Select', 92 | dynamicButtonTextSuffix: 'checked', 93 | disableSearch: 'Disable search', 94 | enableSearch: 'Enable search', 95 | selectGroup: 'Select all:', 96 | allSelectedText: 'All', 97 | }; 98 | 99 | const input = { 100 | searchFilter: $scope.searchFilter || '', 101 | }; 102 | 103 | angular.extend(settings, $scope.extraSettings || []); 104 | angular.extend(externalEvents, $scope.events || []); 105 | angular.extend(texts, $scope.translationTexts); 106 | 107 | if (settings.closeOnBlur) { 108 | $document.on('click', (e) => { 109 | if ($scope.open) { 110 | let target = e.target.parentElement; 111 | let parentFound = false; 112 | 113 | while (angular.isDefined(target) && target !== null && !parentFound) { 114 | if (!!target.className.split && contains(target.className.split(' '), 'multiselect-parent') && !parentFound) { 115 | if (target === $dropdownTrigger) { 116 | parentFound = true; 117 | } 118 | } 119 | target = target.parentElement; 120 | } 121 | 122 | if (!parentFound) { 123 | $scope.$apply(() => { 124 | $scope.close(); 125 | }); 126 | } 127 | } 128 | }); 129 | } 130 | 131 | angular.extend($scope, { 132 | toggleDropdown, 133 | checkboxClick, 134 | externalEvents, 135 | settings, 136 | texts, 137 | input, 138 | close, 139 | selectCurrentGroup, 140 | getGroupLabel, 141 | getButtonText, 142 | getPropertyForObject, 143 | selectAll, 144 | deselectAll, 145 | setSelectedItem, 146 | isChecked, 147 | keyDownLink, 148 | keyDownSearchDefault, 149 | keyDownSearch, 150 | getFilter, 151 | toggleSearch, 152 | keyDownToggleSearch, 153 | orderFunction, 154 | }); 155 | 156 | $scope.externalEvents.onInitDone(); 157 | 158 | function focusFirstOption() { 159 | setTimeout(() => { 160 | const elementToFocus = angular.element($element)[0].querySelector('.option'); 161 | if (angular.isDefined(elementToFocus) && elementToFocus != null) { 162 | elementToFocus.focus(); 163 | } 164 | }, 0); 165 | } 166 | 167 | function toggleDropdown() { 168 | if ($scope.open) { 169 | $scope.close(); 170 | } else { $scope.open = true; } 171 | if ($scope.settings.keyboardControls) { 172 | if ($scope.open) { 173 | if ($scope.settings.selectionLimit === 1 && $scope.settings.enableSearch) { 174 | setTimeout(() => { 175 | angular.element($element)[0].querySelector('.searchField').focus(); 176 | }, 0); 177 | } else { 178 | focusFirstOption(); 179 | } 180 | } 181 | } 182 | if ($scope.settings.enableSearch) { 183 | if ($scope.open) { 184 | setTimeout(() => { 185 | angular.element($element)[0].querySelector('.searchField').focus(); 186 | }, 0); 187 | } 188 | } 189 | } 190 | 191 | function checkboxClick($event, option) { 192 | $scope.setSelectedItem(option, false, true); 193 | $event.stopImmediatePropagation(); 194 | } 195 | 196 | function close() { 197 | $scope.open = false; 198 | $scope.input.searchFilter = $scope.settings.clearSearchOnClose ? '' : $scope.input.searchFilter; 199 | $scope.externalEvents.onClose(); 200 | } 201 | 202 | function selectCurrentGroup(currentGroup) { 203 | $scope.selectedModel.splice(0, $scope.selectedModel.length); 204 | $scope.options.forEach((item) => { 205 | if (item[$scope.settings.groupBy] === currentGroup) { 206 | $scope.setSelectedItem(item, false, false); 207 | } 208 | }); 209 | $scope.externalEvents.onSelectionChanged(); 210 | } 211 | 212 | function getGroupLabel(groupValue) { 213 | if ($scope.settings.groupByTextProvider !== null) { 214 | return $scope.settings.groupByTextProvider(groupValue); 215 | } 216 | 217 | return groupValue; 218 | } 219 | 220 | function textWidth(text) { 221 | const $btn = $element.find('button'); 222 | const canvas = document.createElement('canvas'); 223 | const ctx = canvas.getContext('2d'); 224 | ctx.font = $btn.css('font-size') + $btn.css('font-family'); 225 | // http://stackoverflow.com/questions/38823353/chrome-canvas-2d-context-measuretext-giving-me-weird-results 226 | ctx.originalFont = $btn.css('font-size') + $btn.css('font-family'); 227 | ctx.fillStyle = '#000000'; 228 | return ctx.measureText(text).width; 229 | } 230 | 231 | function getButtonText() { 232 | if ($scope.settings.dynamicTitle && $scope.selectedModel && $scope.selectedModel.length > 0) { 233 | if (angular.isFunction($scope.settings.smartButtonTextProvider)) { 234 | return $scope.settings.smartButtonTextProvider($scope.selectedModel); 235 | } 236 | 237 | if ($scope.settings.smartButtonMaxItems > 0) { 238 | const paddingWidth = 12 * 2; 239 | const borderWidth = 1 * 2; 240 | const dropdownIconWidth = 8; 241 | const widthLimit = $element[0].offsetWidth - paddingWidth - borderWidth - dropdownIconWidth; 242 | 243 | let itemsText = []; 244 | 245 | angular.forEach($scope.options, (optionItem) => { 246 | if ($scope.isChecked(optionItem)) { 247 | const displayText = $scope.getPropertyForObject(optionItem, $scope.settings.displayProp); 248 | const converterResponse = $scope.settings.smartButtonTextConverter(displayText, optionItem); 249 | 250 | itemsText.push(converterResponse || displayText); 251 | } 252 | }); 253 | 254 | if ($scope.selectedModel.length > $scope.settings.smartButtonMaxItems) { 255 | itemsText = itemsText.slice(0, $scope.settings.smartButtonMaxItems); 256 | itemsText.push('...'); 257 | } 258 | 259 | let result = itemsText.join(', '); 260 | let index = result.length - 4; 261 | if ($element[0].offsetWidth === 0) { 262 | return result; 263 | } 264 | if (widthLimit <= textWidth('...')) { 265 | return '...'; 266 | } 267 | while (textWidth(result) > widthLimit) { 268 | if (itemsText[itemsText.length - 1] !== '...') { 269 | itemsText.push('...'); 270 | result = `${result}...`; 271 | index = result.length - 4; 272 | } 273 | result = result.slice(0, index) + result.slice(index + 1); 274 | index -= 1; 275 | } 276 | 277 | return result; 278 | } 279 | const totalSelected = angular.isDefined($scope.selectedModel) ? $scope.selectedModel.length : 0; 280 | 281 | if (totalSelected === 0) { 282 | return $scope.texts.buttonDefaultText; 283 | } 284 | 285 | if ($scope.settings.showAllSelectedText && totalSelected === $scope.options.length) { 286 | return $scope.texts.allSelectedText; 287 | } 288 | 289 | return `${totalSelected} ${$scope.texts.dynamicButtonTextSuffix}`; 290 | } 291 | return $scope.texts.buttonDefaultText; 292 | } 293 | 294 | function getPropertyForObject(object, property) { 295 | if (angular.isDefined(object) && Object.prototype.hasOwnProperty.call(object, property)) { 296 | return object[property]; 297 | } 298 | 299 | return undefined; 300 | } 301 | 302 | function selectAll() { 303 | $scope.deselectAll(true); 304 | $scope.externalEvents.onSelectAll(); 305 | 306 | const searchResult = $filter('filter')($scope.options, $scope.getFilter($scope.input.searchFilter)); 307 | angular.forEach(searchResult, (value) => { 308 | $scope.setSelectedItem(value, true, false); 309 | }); 310 | $scope.externalEvents.onSelectionChanged(); 311 | $scope.selectedGroup = null; 312 | } 313 | 314 | function deselectAll(dontSendEvent = false) { 315 | if (!dontSendEvent) { 316 | $scope.externalEvents.onDeselectAll(); 317 | } 318 | 319 | $scope.selectedModel.splice(0, $scope.selectedModel.length); 320 | if (!dontSendEvent) { 321 | $scope.externalEvents.onSelectionChanged(); 322 | } 323 | $scope.selectedGroup = null; 324 | } 325 | 326 | function setSelectedItem(option, dontRemove = false, fireSelectionChange) { 327 | let exists; 328 | let indexOfOption; 329 | if (angular.isDefined(settings.idProperty)) { 330 | exists = getIndexByProperty($scope.selectedModel, option, settings.idProperty) !== -1; 331 | indexOfOption = getIndexByProperty($scope.selectedModel, option, settings.idProperty); 332 | } else { 333 | exists = $scope.selectedModel.indexOf(option) !== -1; 334 | indexOfOption = $scope.selectedModel.indexOf(option); 335 | } 336 | 337 | if (!dontRemove && exists) { 338 | $scope.selectedModel.splice(indexOfOption, 1); 339 | $scope.externalEvents.onItemDeselect(option); 340 | if ($scope.settings.closeOnDeselect) { 341 | $scope.close(); 342 | } 343 | } else if (!exists && ($scope.settings.selectionLimit === 0 || $scope.selectedModel.length < $scope.settings.selectionLimit)) { 344 | $scope.selectedModel.push(option); 345 | if (fireSelectionChange) { 346 | $scope.externalEvents.onItemSelect(option); 347 | } 348 | if ($scope.settings.closeOnSelect) { 349 | $scope.close(); 350 | } 351 | if ($scope.settings.selectionLimit > 0 && $scope.selectedModel.length === $scope.settings.selectionLimit) { 352 | $scope.externalEvents.onMaxSelectionReached(); 353 | } 354 | } else if ($scope.settings.selectionLimit === 1 && !exists && $scope.selectedModel.length === $scope.settings.selectionLimit) { 355 | $scope.selectedModel.splice(0, 1); 356 | $scope.selectedModel.push(option); 357 | if (fireSelectionChange) { 358 | $scope.externalEvents.onItemSelect(option); 359 | } 360 | if ($scope.settings.closeOnSelect) { 361 | $scope.close(); 362 | } 363 | } 364 | if (fireSelectionChange) { 365 | $scope.externalEvents.onSelectionChanged(); 366 | } 367 | $scope.selectedGroup = null; 368 | } 369 | 370 | function isChecked(option) { 371 | if (angular.isDefined(settings.idProperty)) { 372 | return getIndexByProperty($scope.selectedModel, option, settings.idProperty) !== -1; 373 | } 374 | return $scope.selectedModel.indexOf(option) !== -1; 375 | } 376 | 377 | function keyDownLink(event) { 378 | const sourceScope = angular.element(event.target).scope(); 379 | let nextOption; 380 | let parent = event.target.parentNode; 381 | if (!$scope.settings.keyboardControls) { 382 | return; 383 | } 384 | if (event.keyCode === 13 || event.keyCode === 32) { // enter 385 | event.preventDefault(); 386 | if (sourceScope.option) { 387 | $scope.setSelectedItem(sourceScope.option, false, true); 388 | } else if (event.target.id === 'deselectAll') { 389 | $scope.deselectAll(); 390 | } else if (event.target.id === 'selectAll') { 391 | $scope.selectAll(); 392 | } 393 | } else if (event.keyCode === 38) { // up arrow 394 | event.preventDefault(); 395 | if (parent.previousElementSibling) { 396 | nextOption = parent.previousElementSibling.querySelector('a') || parent.previousElementSibling.querySelector('input'); 397 | } 398 | while (!nextOption && !!parent) { 399 | parent = parent.previousElementSibling; 400 | if (parent) { 401 | nextOption = parent.querySelector('a') || parent.querySelector('input'); 402 | } 403 | } 404 | if (nextOption) { 405 | nextOption.focus(); 406 | } 407 | } else if (event.keyCode === 40) { // down arrow 408 | event.preventDefault(); 409 | if (parent.nextElementSibling) { 410 | nextOption = parent.nextElementSibling.querySelector('a') || parent.nextElementSibling.querySelector('input'); 411 | } 412 | while (!nextOption && !!parent) { 413 | parent = parent.nextElementSibling; 414 | if (parent) { 415 | nextOption = parent.querySelector('a') || parent.querySelector('input'); 416 | } 417 | } 418 | if (nextOption) { 419 | nextOption.focus(); 420 | } 421 | } else if (event.keyCode === 27) { 422 | event.preventDefault(); 423 | 424 | $scope.toggleDropdown(); 425 | } 426 | } 427 | 428 | function keyDownSearchDefault(event) { 429 | let parent = event.target.parentNode.parentNode; 430 | let nextOption; 431 | if (!$scope.settings.keyboardControls) { 432 | return; 433 | } 434 | if (event.keyCode === 9 || event.keyCode === 40) { // tab 435 | event.preventDefault(); 436 | focusFirstOption(); 437 | } else if (event.keyCode === 38) { 438 | event.preventDefault(); 439 | if (parent.previousElementSibling) { 440 | nextOption = parent.previousElementSibling.querySelector('a') || parent.previousElementSibling.querySelector('input'); 441 | } 442 | while (!nextOption && !!parent) { 443 | parent = parent.previousElementSibling; 444 | if (parent) { 445 | nextOption = parent.querySelector('a') || parent.querySelector('input'); 446 | } 447 | } 448 | if (nextOption) { 449 | nextOption.focus(); 450 | } 451 | } else if (event.keyCode === 27) { 452 | event.preventDefault(); 453 | 454 | $scope.toggleDropdown(); 455 | } 456 | } 457 | 458 | function keyDownSearch(event, searchFilter) { 459 | let searchResult; 460 | if (!$scope.settings.keyboardControls) { 461 | return; 462 | } 463 | if (event.keyCode === 13) { 464 | if ($scope.settings.selectionLimit === 1 && $scope.settings.enableSearch) { 465 | searchResult = $filter('filter')($scope.options, $scope.getFilter(searchFilter)); 466 | if (searchResult.length === 1) { 467 | $scope.setSelectedItem(searchResult[0], false, true); 468 | } 469 | } else if ($scope.settings.enableSearch) { 470 | $scope.selectAll(); 471 | } 472 | } 473 | } 474 | 475 | function getFilter(searchFilter) { 476 | const filter = {}; 477 | filter[$scope.settings.searchField] = searchFilter; 478 | return filter; 479 | } 480 | 481 | function toggleSearch($event) { 482 | if ($event) { 483 | $event.stopPropagation(); 484 | } 485 | $scope.settings.enableSearch = !$scope.settings.enableSearch; 486 | if (!$scope.settings.enableSearch) { 487 | $scope.input.searchFilter = ''; 488 | } 489 | } 490 | 491 | function keyDownToggleSearch() { 492 | if (!$scope.settings.keyboardControls) { 493 | return; 494 | } 495 | if (event.keyCode === 13) { 496 | $scope.toggleSearch(); 497 | if ($scope.settings.enableSearch) { 498 | setTimeout( 499 | () => { 500 | angular.element($element)[0].querySelector('.searchField').focus(); 501 | }, 0, 502 | ); 503 | } else { 504 | focusFirstOption(); 505 | } 506 | } 507 | } 508 | 509 | function orderFunction(object1, object2) { 510 | if (angular.isUndefined(object2)) { 511 | return -1; 512 | } 513 | if (angular.isUndefined(object1)) { 514 | return 1; 515 | } 516 | if (object1.type !== 'object' || object2.type !== 'object') { 517 | return (object1.index < object2.index) ? -1 : 1; 518 | } 519 | const v1 = object1.value; 520 | const v2 = object2.value; 521 | // first order by group 522 | if ($scope.settings.groupBy) { 523 | if (v1[$scope.settings.groupBy] !== v2[$scope.settings.groupBy]) { 524 | if (v1[$scope.settings.groupBy] < v2[$scope.settings.groupBy]) { 525 | return 1; 526 | } 527 | return -1; 528 | } 529 | } 530 | if (!$scope.settings.selectedToTop) { 531 | return $scope.options.indexOf(v1) < $scope.options.indexOf(v2) ? -1 : 1; 532 | } 533 | // then order selected to top 534 | if ((!$scope.isChecked(v1) && !$scope.isChecked(v2)) || 535 | ($scope.isChecked(v1) && $scope.isChecked(v2))) { 536 | return $scope.options.indexOf(v1) < $scope.options.indexOf(v2) ? -1 : 1; 537 | } 538 | if ($scope.isChecked(v1)) { 539 | return -1; 540 | } 541 | return 1; 542 | } 543 | } 544 | -------------------------------------------------------------------------------- /src/app/component/angularjs-dropdown-multiselect.directive.js: -------------------------------------------------------------------------------- 1 | import controller from './angularjs-dropdown-multiselect.controller'; 2 | 3 | export default function dropdownMultiselectDirective() { 4 | return { 5 | restrict: 'AE', 6 | scope: { 7 | selectedModel: '=', 8 | options: '=', 9 | extraSettings: '=', 10 | events: '=', 11 | searchFilter: '=?', 12 | translationTexts: '=', 13 | disabled: '=', 14 | }, 15 | transclude: { 16 | toggleDropdown: '?toggleDropdown', 17 | }, 18 | controller, 19 | templateUrl: 'app/component/angularjs-dropdown-multiselect.html', 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/component/angularjs-dropdown-multiselect.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/component/angularjs-dropdown-multiselect.module.js: -------------------------------------------------------------------------------- 1 | import dropdownDirective from './angularjs-dropdown-multiselect.directive'; 2 | 3 | angular.module('angularjs-dropdown-multiselect', []) 4 | .directive('dmDropdownStaticInclude', ($compile) => { 5 | 'ngInject'; 6 | 7 | return function directive(scope, element, attrs) { 8 | const template = attrs.dmDropdownStaticInclude; 9 | const contents = element.html(template).contents(); 10 | $compile(contents)(scope); 11 | }; 12 | }) 13 | .directive('ngDropdownMultiselect', dropdownDirective); 14 | -------------------------------------------------------------------------------- /src/app/component/index.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Do not remove the comments below. It's the markers used by wiredep to inject 3 | * sass dependencies when defined in the bower.json of your dependencies 4 | */ 5 | // bower:scss 6 | // endbower 7 | 8 | /** 9 | * Do not remove the comments below. It's the markers used by gulp-inject to inject 10 | * all your sass files automatically 11 | */ 12 | // injector 13 | // endinjector 14 | -------------------------------------------------------------------------------- /src/app/index.module.js: -------------------------------------------------------------------------------- 1 | import './component/angularjs-dropdown-multiselect.module'; 2 | import component from './main/main.component'; 3 | import v1component from './v1docs/v1docs.component'; 4 | 5 | angular.module('AngularjsDropdownMultiselectExample', [ 6 | 'angularjs-dropdown-multiselect', 7 | 'hljs', 8 | 'ui.bootstrap', 9 | 'ui.router', 10 | ]) 11 | .component('main', component()) 12 | .component('v1Docs', v1component()) 13 | .config(($stateProvider, $urlRouterProvider) => { 14 | $stateProvider.state({ 15 | name: 'main', 16 | url: '/main', 17 | template: '
', 18 | }); 19 | 20 | $stateProvider.state({ 21 | name: 'v1', 22 | url: '/v1', 23 | template: '', 24 | }); 25 | 26 | $urlRouterProvider.otherwise('/main'); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/index.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * If you want to override some bootstrap variables, you have to change values here. 3 | * The list of variables are listed here bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 4 | */ 5 | $navbar-inverse-link-color: #5AADBB; 6 | $icon-font-path: "../../bower_components/bootstrap-sass/assets/fonts/bootstrap/"; 7 | 8 | /** 9 | * Do not remove the comments below. It's the markers used by wiredep to inject 10 | * sass dependencies when defined in the bower.json of your dependencies 11 | */ 12 | // bower:scss 13 | // endbower 14 | 15 | .browsehappy { 16 | margin: 0.2em 0; 17 | background: #ccc; 18 | color: #000; 19 | padding: 0.2em 0; 20 | } 21 | 22 | .thumbnail { 23 | height: 200px; 24 | 25 | img.pull-right { 26 | width: 50px; 27 | } 28 | } 29 | 30 | body { 31 | background-color: #efefef; 32 | height: 100vh; 33 | } 34 | 35 | main { 36 | height: 100%; 37 | 38 | > section { 39 | padding-top: 1em; 40 | background-color: #fefefe; 41 | height: calc(100% - 135px); 42 | overflow: auto; 43 | 44 | h2 { 45 | font-size: 1.5em; 46 | color: #2e7bcf; 47 | } 48 | 49 | h3 { 50 | font-size: 1.2em; 51 | color: #2e7bcf; 52 | } 53 | } 54 | } 55 | 56 | header { 57 | padding: 40px; 58 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 59 | background: #2e7bcf; 60 | border-bottom: solid 1px #275da1; 61 | height: 135px; 62 | 63 | h1 { 64 | letter-spacing: -1px; 65 | font-size: 2em; 66 | color: #fff; 67 | line-height: 1; 68 | margin-bottom: 0.2em; 69 | margin-top: 0.2em; 70 | width: auto; 71 | } 72 | } 73 | 74 | /** 75 | * Do not remove the comments below. It's the markers used by gulp-inject to inject 76 | * all your sass files automatically 77 | */ 78 | // injector 79 | // endinjector 80 | -------------------------------------------------------------------------------- /src/app/main/main.component.js: -------------------------------------------------------------------------------- 1 | import controller from './main.controller'; 2 | 3 | export default function mainComponent() { 4 | const component = { 5 | templateUrl: 'app/main/main.template.html', 6 | controller, 7 | }; 8 | 9 | return component; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/main/main.controller.js: -------------------------------------------------------------------------------- 1 | /* 2 | eslint no-param-reassign: [ 3 | "error", 4 | { 5 | "props": true, 6 | "ignorePropertyModificationsFor": [ 7 | "$scope" 8 | ] 9 | } 10 | ] 11 | */ 12 | 13 | export default class MainController { 14 | constructor( 15 | $scope, 16 | $log, 17 | ) { 18 | 'ngInject'; 19 | 20 | $scope.testing = true; 21 | $scope.testmodel = [{ id: 1 }]; 22 | $scope.testdata = [ 23 | { id: 1, label: 'David' }, 24 | { id: 2, label: 'Jhon' }, 25 | { id: 3, label: 'Danny' }, 26 | ]; 27 | $scope.testsettings = { 28 | selectionLimit: 1, 29 | selectedToTop: true, 30 | idProperty: 'id', 31 | }; 32 | $scope.testevents = { 33 | onSelectionChanged() { // This event is not firing on selection of max limit 34 | $log.debug('you changed selection'); 35 | }, 36 | }; 37 | 38 | $scope.example1model = []; 39 | $scope.example1data = [ 40 | { id: 1, label: 'David' }, 41 | { id: 2, label: 'Jhon' }, 42 | { id: 3, label: 'Danny' }, 43 | ]; 44 | 45 | $scope.example2model = []; 46 | $scope.example2data = [ 47 | { id: 1, label: 'David' }, 48 | { id: 2, label: 'Jhon' }, 49 | { id: 3, label: 'Danny' }, 50 | ]; 51 | $scope.example2settings = { displayProp: 'id' }; 52 | 53 | $scope.example5model = []; 54 | $scope.example5data = [ 55 | { id: 1, label: 'David' }, 56 | { id: 2, label: 'Jhon' }, 57 | { id: 3, label: 'Danny' }, 58 | ]; 59 | $scope.example5settings = {}; 60 | $scope.example5customTexts = { buttonDefaultText: 'Select Users' }; 61 | 62 | $scope.example6data = [ 63 | { id: 1, label: 'David' }, 64 | { id: 2, label: 'Jhon' }, 65 | { id: 3, label: 'Danny' }]; 66 | $scope.example6model = [$scope.example6data[0], $scope.example6data[2]]; 67 | $scope.example6settings = {}; 68 | 69 | $scope.example7model = []; 70 | $scope.example7data = [ 71 | { id: 1, label: 'David' }, 72 | { id: 2, label: 'Jhon' }, 73 | { id: 3, label: 'Danny' }, 74 | ]; 75 | $scope.example7settings = { externalIdProp: '' }; 76 | $scope.customFilter = 'a'; 77 | 78 | $scope.example8model = []; 79 | $scope.example8data = [ 80 | { id: 1, label: 'David' }, 81 | { id: 2, label: 'Jhon' }, 82 | { id: 3, label: 'Danny' }, 83 | ]; 84 | $scope.example8settings = { 85 | checkBoxes: true, 86 | }; 87 | 88 | $scope.example9model = []; 89 | $scope.example9data = [ 90 | { id: 1, label: 'David' }, 91 | { id: 2, label: 'Jhon' }, 92 | { id: 3, label: 'Danny' }]; 93 | $scope.example9settings = { enableSearch: true }; 94 | 95 | $scope.example10model = []; 96 | $scope.example10data = [ 97 | { id: 1, label: 'David' }, 98 | { id: 2, label: 'Jhon' }, 99 | { id: 3, label: 'Danny' }]; 100 | 101 | $scope.example10settings = { selectionLimit: 2 }; 102 | 103 | $scope.example12model = []; 104 | $scope.example12data = [ 105 | { id: 1, label: 'David' }, 106 | { id: 2, label: 'Jhon' }, 107 | { id: 3, label: 'Danny' }]; 108 | 109 | $scope.example12settings = { selectionLimit: 1 }; 110 | 111 | 112 | $scope.example11model = []; 113 | $scope.example11data = [ 114 | { id: 1, label: 'David', gender: 'M' }, 115 | { id: 2, label: 'Jhon', gender: 'M' }, 116 | { id: 3, label: 'Lisa', gender: 'F' }, 117 | { id: 4, label: 'Nicole', gender: 'F' }, 118 | { id: 5, label: 'Danny', gender: 'M' }]; 119 | 120 | $scope.example11settings = { 121 | groupByTextProvider(groupValue) { 122 | if (groupValue === 'M') { 123 | return 'Male'; 124 | } 125 | return 'Female'; 126 | }, 127 | groupBy: 'gender', 128 | }; 129 | 130 | $scope.selectByGroupModel = []; 131 | $scope.selectByGroupData = [ 132 | { id: 1, label: 'David', gender: 'M' }, 133 | { id: 2, label: 'Jhon', gender: 'M' }, 134 | { id: 3, label: 'Lisa', gender: 'F' }, 135 | { id: 4, label: 'Nicole', gender: 'F' }, 136 | { id: 5, label: 'Danny', gender: 'M' }, 137 | { id: 6, label: 'Unknown', gender: 'O' }]; 138 | 139 | $scope.selectByGroupSettings = { 140 | selectByGroups: ['F', 'M'], 141 | groupByTextProvider(groupValue) { 142 | switch (groupValue) { 143 | case 'M': 144 | return 'Male'; 145 | case 'F': 146 | return 'Female'; 147 | default: 148 | return 'Other'; 149 | } 150 | }, 151 | groupBy: 'gender', 152 | }; 153 | 154 | $scope.example13model = []; 155 | $scope.example13data = [ 156 | { id: 1, label: 'David' }, 157 | { id: 2, label: 'Jhon' }, 158 | { id: 3, label: 'Lisa' }, 159 | { id: 4, label: 'Nicole' }, 160 | { id: 5, label: 'Danny' }]; 161 | 162 | $scope.example13settings = { 163 | smartButtonMaxItems: 3, 164 | smartButtonTextConverter(itemText) { 165 | if (itemText === 'Jhon') { 166 | return 'Jhonny!'; 167 | } 168 | 169 | return itemText; 170 | }, 171 | }; 172 | 173 | $scope.example14model = []; 174 | $scope.example14data = [ 175 | { id: 1, label: 'David' }, 176 | { id: 2, label: 'Jhon' }, 177 | { id: 3, label: 'Lisa' }, 178 | { id: 4, label: 'Nicole' }, 179 | { id: 5, label: 'Danny' }, 180 | { id: 6, label: 'Dan' }, 181 | { id: 7, label: 'Dean' }, 182 | { id: 8, label: 'Adam' }, 183 | { id: 9, label: 'Uri' }, 184 | { id: 10, label: 'Phil' }]; 185 | 186 | $scope.example14settings = { 187 | scrollableHeight: '100px', 188 | scrollable: true, 189 | }; 190 | 191 | $scope.example15model = []; 192 | $scope.example15data = [ 193 | { id: 1, label: 'David' }, 194 | { id: 2, label: 'Jhon' }, 195 | { id: 3, label: 'Lisa' }, 196 | { id: 4, label: 'Nicole' }, 197 | { id: 5, label: 'Danny' }]; 198 | 199 | $scope.example15settings = { 200 | enableSearch: true, 201 | }; 202 | 203 | $scope.example16model = []; 204 | $scope.example16data = [ 205 | { id: 1, label: 'David' }, 206 | { id: 2, label: 'Jhon' }, 207 | { id: 3, label: 'Lisa' }, 208 | { id: 4, label: 'Nicole' }, 209 | { id: 5, label: 'Danny' }]; 210 | $scope.example16settings = { 211 | styleActive: true, 212 | }; 213 | 214 | $scope.example17model = []; 215 | $scope.example17data = [ 216 | { id: 1, label: 'David' }, 217 | { id: 2, label: 'Jhon' }, 218 | { id: 3, label: 'Lisa' }, 219 | { id: 4, label: 'Nicole' }, 220 | { id: 5, label: 'Danny' }]; 221 | $scope.example17settings = { 222 | keyboardControls: true, 223 | }; 224 | 225 | $scope.example18model = []; 226 | $scope.example18data = [ 227 | { id: 1, label: 'David' }, 228 | { id: 2, label: 'Jhon' }, 229 | { id: 3, label: 'Lisa' }, 230 | { id: 4, label: 'Nicole' }, 231 | { id: 5, label: 'Danny' }]; 232 | $scope.example18settings = { 233 | keyboardControls: true, 234 | enableSearch: true, 235 | selectionLimit: 1, 236 | }; 237 | 238 | $scope.example19model = []; 239 | $scope.example19data = [ 240 | { id: 1, name: 'David' }, 241 | { id: 2, name: 'Jhon' }, 242 | { id: 3, name: 'Lisa' }, 243 | { id: 4, name: 'Nicole' }, 244 | { id: 5, name: 'Danny' }]; 245 | $scope.example19settings = { 246 | template: '{{option.name}}', 247 | }; 248 | 249 | $scope.example20model = []; 250 | $scope.example20data = [ 251 | { id: 1, label: 'David', age: 23 }, 252 | { id: 2, label: 'Jhon', age: 24 }, 253 | { id: 3, label: 'Danny', age: 26 }]; 254 | $scope.example20settings = { 255 | searchField: 'age', 256 | enableSearch: true, 257 | }; 258 | 259 | $scope.example21model = []; 260 | $scope.example21data = [ 261 | { id: 1, label: 'David' }, 262 | { id: 2, label: 'Jhon' }, 263 | { id: 3, label: 'Danny' }]; 264 | $scope.example21settings = { 265 | showEnableSearchButton: true, 266 | }; 267 | 268 | $scope.searchSelectAllModel = []; 269 | $scope.searchSelectAllData = [ 270 | { id: 1, label: 'David' }, 271 | { id: 2, label: 'Jhon' }, 272 | { id: 3, label: 'Danny' }, 273 | ]; 274 | $scope.searchSelectAllSettings = { 275 | enableSearch: true, 276 | keyboardControls: true, 277 | }; 278 | 279 | $scope.disabledModel = []; 280 | $scope.disabledData = [ 281 | { id: 1, label: 'David', disabled: true }, 282 | { id: 2, label: 'Jhon' }, 283 | { id: 3, label: 'Danny' }, 284 | ]; 285 | 286 | $scope.selectedToTopModel = []; 287 | $scope.selectedToTopData = [ 288 | { id: 1, label: 'David' }, 289 | { id: 2, label: 'Jhon' }, 290 | { id: 3, label: 'Danny' }, 291 | ]; 292 | $scope.selectedToTopSettings = { 293 | selectedToTop: true, 294 | }; 295 | 296 | $scope.stringModel = []; 297 | $scope.stringData = [ 298 | 'David', 299 | 'Jhon', 300 | 'Danny', 301 | ]; 302 | $scope.stringSettings = { 303 | template: '{{option}}', 304 | smartButtonTextConverter(skip, option) { 305 | return option; 306 | }, 307 | }; 308 | 309 | $scope.transclusionModel = []; 310 | $scope.transclusionData = [ 311 | { id: 1, label: 'David' }, 312 | { id: 2, label: 'Jhon' }, 313 | { id: 3, label: 'Danny' }, 314 | ]; 315 | $scope.transclusionSettings = { 316 | }; 317 | 318 | $scope.idPropertyModel = [{ id: 1 }]; 319 | $scope.idPropertyData = [ 320 | { id: 1, label: 'David' }, 321 | { id: 2, label: 'Jhon' }, 322 | { id: 3, label: 'Danny' }, 323 | ]; 324 | $scope.idPropertySettings = { 325 | idProperty: 'id', 326 | }; 327 | 328 | $scope.smartButtonTextProviderModel = [ 329 | ]; 330 | $scope.smartButtonTextProviderData = [ 331 | { id: 1, label: 'David' }, 332 | { id: 2, label: 'Jhon' }, 333 | { id: 3, label: 'Danny' }, 334 | ]; 335 | $scope.smartButtonTextProviderSettings = { 336 | smartButtonTextProvider(selectionArray) { 337 | return selectionArray.length + 2; 338 | }, 339 | }; 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/app/main/main.template.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

What is AngularJS Dropdown Multiselect?

5 | This directive uses Bootstrap's Dropdown with the power of AngularJS directives and binding. Bootstrap and AngularJS are the only dependencies. 6 |
7 |
In this page you can see basic and advanced usage examples. 8 |
9 |
10 |
11 |
12 |

Download

13 | There are several options to do that: 14 |
    15 |
  1. Using bower: `bower install angularjs-dropdown-multiselect`
  2. 16 |
  3. Using npm: `npm install angularjs-dropdown-multiselect`
  4. 17 |
  5. 18 | Download the .zip file from here 19 |
  6. 20 |
21 | This is documentation for the currently still in beta v2.0.0, the documentation for v1 can be found here: 22 | V1 docs 23 |
24 |
25 | 26 |
28 |
29 |
30 | test 31 |
32 |
33 |
34 |
35 |

Demo

36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |

The model:

44 |
{{testmodel|json}}
45 |
46 |
47 |
48 |
49 |
50 |
51 |

Demo

52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |

The model:

60 |
{{example1model|json}}
61 |
62 |
63 |
64 |
65 |

Code

66 |
67 | // HTML 68 |
69 | 70 | // JavaScript $scope.example1model = []; 71 | $scope.example1data = [ 72 | {id: 1, label: "David"}, 73 | {id: 2, label: "Jhon"}, 74 | {id: 3, label: "Danny"} 75 | ]; 76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | This example shows the ability to select the property to display as text label. 84 |
In this case, the property the used as label is "id". 85 |
86 |
87 |
88 |
89 |

Demo

90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |

The model:

98 |
{{example2model|json}}
99 |
100 |
101 |
102 |
103 |

Code

104 |
105 | // HTML 106 |
107 | 108 | // JavaScript $scope.example2model = []; $scope.example2data = [ {id: 1, label: "David"}, {id: 2, label: "Jhon"}, {id: 3, label: "Danny"}]; $scope.example2settings = {displayProp: 'id'}; 109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | You can use the feature in order to show which items are selected instead the items count.
117 | In order to use this feature, set the "smartButtonMaxItems" settings parameter to a number bigger than 0.
118 | You can also provide "smartButtonTextConverter" parameter in order to add smart logic and convert the text. 119 |
120 |
121 |
122 |
123 |

Demo

124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |

The model:

132 |
{{example13model|json}}
133 |
134 |
135 |
136 |
137 |

Code

138 |
139 | //HTML 140 |
141 | 142 | //JS 143 | $scope.example13model = []; 144 | $scope.example13data = [ 145 | {id: 1, label: "David"}, 146 | {id: 2, label: "Jhon"}, 147 | {id: 3, label: "Lisa"}, 148 | {id: 4, label: "Nicole"}, 149 | {id: 5, label: "Danny"} 150 | ]; 151 | 152 | $scope.example13settings = { 153 | smartButtonMaxItems: 3, 154 | smartButtonTextConverter: function(itemText, originalItem) { 155 | if (itemText === 'Jhon') { 156 | return 'Jhonny!'; 157 | } 158 | 159 | return itemText; 160 | } 161 | }; 162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | You can use the feature in order to make the list of items scrollable. Useful when you deal with a lot of items. 170 |
171 |
172 |
173 |
174 |

Demo

175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |

The model:

183 |
{{example14model|json}}
184 |
185 |
186 |
187 |
188 |

Code

189 |
190 | //HTML 191 |
192 | 193 | //JS 194 | $scope.example14model = []; 195 | $scope.example14data = [ 196 | {id: 1, label: "David"}, 197 | {id: 2, label: "Jhon"}, 198 | {id: 3, label: "Lisa"}, 199 | {id: 4, label: "Nicole"}, 200 | {id: 5, label: "Danny"}, 201 | {id: 6, label: "Dan"}, 202 | {id: 7, label: "Dean"}, 203 | {id: 8, label: "Adam"}, 204 | {id: 9, label: "Uri"}, 205 | {id: 10, label: "Phil"} 206 | ]; 207 | 208 | $scope.example14settings = { 209 | scrollableHeight: '100px', 210 | scrollable: true 211 | }; 212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |

Demo

220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |

The model:

228 |
{{example9model|json}}
229 |
230 |
231 |
232 |
233 |

Code

234 |
235 | // HTML 236 |
237 | 238 | // JavaScript $scope.example9model = []; $scope.example9data = [ {id: 1, label: "David"}, {id: 2, label: "Jhon"}, {id: 3, label: "Danny"}]; $scope.example9settings = {enableSearch: true}; 239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 | By default, search is done on all items, by specifying the searchField in the settings object one can specify on which field of the objects the filtering should be done. 247 |
248 |
249 |
250 |
251 |

Demo

252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |

The model:

260 |
{{example20model|json}}
261 |
262 |
263 |
264 |
265 |

Code

266 |
267 | // HTML 268 |
269 | 270 | // JavaScript 271 | $scope.example20model = []; 272 | $scope.example20data = [ 273 | { id: 1, label: "David", age: 23 }, 274 | { id: 2, label: "Jhon", age: 24 }, 275 | { id: 3, label: "Danny", age: 26 } 276 | ]; 277 | $scope.example20settings = { 278 | searchField: 'age', 279 | enableSearch: true 280 | }; 281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 | Setting showEnableSearchButton to true will add the enable/disable search button under the Select all / Deselect all buttons 289 |
290 |
291 |
292 |
293 |

Demo

294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |

The model:

302 |
{{example21model|json}}
303 |
304 |
305 |
306 |
307 |

Code

308 |
309 | // HTML 310 |
311 | 312 | // JavaScript 313 | $scope.example21model = []; 314 | $scope.example21data = [ 315 | { id: 1, label: "David"}, 316 | { id: 2, label: "Jhon"}, 317 | { id: 3, label: "Danny"} 318 | ]; 319 | $scope.example21settings = { 320 | showEnableSearchButton: true 321 | }; 322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |

Demo

330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |

The model:

338 |
{{searchSelectAllModel|json}}
339 |
340 |
341 |
342 |
343 |

Code

344 |
345 | // HTML 346 |
347 | // JavaScript 348 | $scope.searchSelectAllModel = []; 349 | $scope.searchSelectAllData = [ 350 | {id: 1, label: "David"}, 351 | {id: 2, label: "Jhon"}, 352 | {id: 3, label: "Danny"} 353 | ]; 354 | $scope.searchSelectAllSettings = { 355 | enableSearch: true, 356 | showSelectAll: true, 357 | keyboardControls: true 358 | }; 359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 | By default, there is no limit on the maximum selected items. 367 |
You can limit the selection by providing selectionLimit using the settings attribute. 368 |
369 | Note 1: limit the selection to 0 is the default and won't limit the selection! 370 |
371 | Note 2: When using this limit, the "Select All" button will not appear! 372 |
373 |
374 | 375 | Note 3: When using single selection (limit to 1) the selection will change 376 | automaticlly if another item is clicked! 377 | 378 |
379 |
380 |
381 |
382 |

Demo

383 |
384 |
385 |
386 |
387 |
388 |

The model:

389 |
{{example10model|json}}
390 |
391 |
392 |
393 |
394 |

Code

395 |
396 | // HTML 397 |
398 | 399 | // JavaScript $scope.example10model = []; $scope.example10data = [ {id: 1, label: "David"}, {id: 2, label: "Jhon"}, {id: 3, label: "Danny"}]; $scope.example10settings = {selectionLimit: 2}; 400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 | Please read the notes in the "Selection Limit" example. 408 |
This example shows an example of using selection limit and single selection. 409 |
410 |
411 |
412 |
413 |

Demo

414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |

The model:

422 |
{{example12model|json}}
423 |
424 |
425 |
426 |
427 |

Code

428 |
429 | // HTML 430 |
431 | 432 | // JavaScript 433 | $scope.example12model = {}; // ! IMPORTANT ! 434 | $scope.example12data = [ 435 | {id: 1, label: "David"}, 436 | {id: 2, label: "Jhon"}, 437 | {id: 3, label: "Danny"} 438 | ]; 439 | $scope.example12settings = { 440 | selectionLimit: 1, 441 | }; 442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 | You can also group the items by propery that you want, in order to to that, provide the groupBy setting. 450 |
Also, you need to provide "groupByTextProvider" callback in the extra-settings attribute, in order to provide the header text for each group. 451 |
452 | 453 | Note: If you won't specify the "groupByTextProvider" callback in order to get the 454 | header for each group, the value of the group will be displayed! 455 | 456 |
457 |
458 |
459 |
460 |

Demo

461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |

The model:

469 |
{{example11model|json}}
470 |
471 |
472 |
473 |
474 |

Code

475 |
476 | // HTML 477 |
478 | 479 | // JavaScript 480 | $scope.example11model = []; 481 | $scope.example11data = [ 482 | {id: 1, label: "David", gender: 'M'}, 483 | {id: 2, label: "Jhon", gender: 'M'}, 484 | {id: 3, label: "Lisa", gender: 'F'}, 485 | {id: 4, label: "Nicole", gender: 'F'}, 486 | {id: 5, label: "Danny", gender: 'M'} 487 | ]; 488 | $scope.example11settings = { 489 | groupByTextProvider: function(groupValue) { 490 | if (groupValue === 'M') { 491 | return 'Male'; 492 | } else { 493 | return 'Female'; 494 | } 495 | }, 496 | groupBy: 'gender', 497 | }; 498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 | When items are grouped by property you can also specify an array of groups that you can use to select the items by. 506 | The extra-settings property selectByGroups accepts an array of the values of the groups that you want to be selectable. 507 | The naming will use the groupByTextProvider function to give them an actual label. 508 |
509 |
510 |
511 |
512 |

Demo

513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |

The model:

521 |
{{selectByGroupModel|json}}
522 |
523 |
524 |
525 |
526 |

Code

527 |
528 | // HTML 529 |
530 | 531 | // JavaScript 532 | $scope.selectByGroupModel = []; 533 | $scope.selectByGroupData = [ 534 | { id: 1, label: "David", gender: 'M' }, 535 | { id: 2, label: "Jhon", gender: 'M' }, 536 | { id: 3, label: "Lisa", gender: 'F' }, 537 | { id: 4, label: "Nicole", gender: 'F' }, 538 | { id: 5, label: "Danny", gender: 'M' }, 539 | { id: 6, label: "Unknown", gender: 'O' } 540 | ]; 541 | 542 | $scope.selectByGroupSettings = { 543 | selectByGroups: ['F', 'M'], 544 | groupByTextProvider: function(groupValue) { 545 | switch (groupValue) { 546 | case 'M': 547 | return 'Male'; 548 | case 'F': 549 | return 'Female'; 550 | case 'O': 551 | return 'Other'; 552 | } 553 | }, 554 | groupBy: 'gender', 555 | }; 556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 | You can select your own text of the button using the "defaultText" in settings. 564 |
565 |
566 |
567 |
568 |

Demo

569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |

The model:

577 |
{{example5model|json}}
578 |
579 |
580 |
581 |
582 |

Code

583 |
584 | // HTML 585 |
586 | 587 | // JavaScript $scope.example5model = []; $scope.example5data = [ {id: 1, label: "David"}, {id: 2, label: "Jhon"}, {id: 3, label: "Danny"}]; $scope.example5settings = {}; $scope.example5customTexts = {buttonDefaultText: 'Select Users'}; 588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 | This example shows a demostration of using a pre-setted model. 596 |
597 | Note:The model should have the same objects as in the options array. 598 |
599 |
600 |
601 |
602 |

Demo

603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |

The model:

611 |
{{example6model|json}}
612 |
613 |
614 |
615 |
616 |

Code

617 |
618 | // HTML 619 |
620 | 621 | // JavaScript 622 | $scope.example6data = [ 623 | { id: 1, label: 'David' }, 624 | { id: 2, label: 'Jhon' }, 625 | { id: 3, label: 'Danny' } 626 | ]; 627 | $scope.example6model = [$scope.example6data[0], $scope.example6data[2]]; 628 | $scope.example6settings = {}; 629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 | This example shows a demostration of access and set the search filter from outside the directive. 637 |
This can be done by settings the "search-filter" attribute. 638 |
639 |
640 |
641 |
642 |
643 |

Demo

644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |

The model:

652 |
{{example7model|json}}
653 |

Search Filter:

654 |
{{customFilter|json}}
655 |
656 |
657 |
658 |
659 |

Code

660 |
661 | // HTML 662 |
663 | 664 | // JavaScript 665 | 666 | $scope.example15model = []; 667 | $scope.example15data = [ 668 | {id: 1, label: "David"}, 669 | {id: 2, label: "Jhon"}, 670 | {id: 3, label: "Lisa"}, 671 | {id: 4, label: "Nicole"}, 672 | {id: 5, label: "Danny"} 673 | ]; 674 | 675 | $scope.example15settings = { 676 | enableSearch: true 677 | }; 678 | 679 | $scope.customFilter = 'a'; 680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 | You can also use a checkboxes list by setting checkBoxes setting to true! 688 |
689 |
690 |
691 |
692 |

Demo

693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |

The model:

701 |
{{example8model|json}}
702 |
703 |
704 |
705 |
706 |

Code

707 |
708 | // HTML 709 |
710 | 711 | // JavaScript $scope.example8model = []; 712 | $scope.example8data = [ 713 | {id: 1, label: "David"}, 714 | {id: 2, label: "Jhon"}, 715 | {id: 3, label: "Danny"} 716 | ]; 717 | $scope.example8settings = { 718 | checkBoxes: true, 719 | }; 720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |

Demo

728 | You can also aplly the active class to the selected list items. This can be done by setting the styleActive setting to true 729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |

The model:

737 |
{{example16model|json}}
738 |
739 |
740 |
741 |
742 |

Code

743 |
744 | // HTML 745 |
746 | 747 | // JavaScript 748 | $scope.example16model = []; $scope.example16data = [ {id: 1, label: "David"}, {id: 2, label: "Jhon"}, {id: 3, label: "Danny"}]; $scope.example16settings = {styleActive: true}; 749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |

Demo

757 | When activated the dropdown can be used with the keyboard instead of with the mouse. Up, down arrow change focused element, escape closes the dropdown, enter and space activate focused element. 758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |

The model:

766 |
{{example17model|json}}
767 |
768 |
769 |
770 |
771 |

Code

772 |
773 | // HTML 774 |
775 | 776 | // JavaScript 777 | $scope.example17model = []; $scope.example17data = [ {id: 1, label: "David"}, {id: 2, label: "Jhon"}, {id: 3, label: "Danny"}]; $scope.example17settings = {keyboardControls: true}; 778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |

Demo

786 | When search is enabled and a single selection is active, wehn search returns a single match pressing enter in the search box will activate the matched option. 787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |

The model:

795 |
{{example18model|json}}
796 |
797 |
798 |
799 |
800 |

Code

801 |
802 | // HTML 803 |
804 | 805 | // JavaScript 806 | $scope.example18model = {}; 807 | $scope.example18data = [ 808 | { id: 1, label: "David" }, 809 | { id: 2, label: "Jhon" }, 810 | { id: 3, label: "Lisa" }, 811 | { id: 4, label: "Nicole" }, 812 | { id: 5, label: "Danny" } 813 | ]; 814 | $scope.example18settings = { 815 | keyboardControls: true, 816 | enableSearch: true, 817 | selectionLimit: 1 818 | }; 819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |

Demo

827 | Instead of using the default template you can use an own custom temlpate. 828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |

The model:

836 |
{{example19model|json}}
837 |
838 |
839 |
840 |
841 |

Code

842 |
843 | // HTML 844 |
845 | 846 | // JavaScript 847 | $scope.example19model = {}; 848 | $scope.example19data = [ 849 | { id: 1, name: "David" }, 850 | { id: 2, name: "Jhon" }, 851 | { id: 3, name: "Lisa" }, 852 | { id: 4, name: "Nicole" }, 853 | { id: 5, name: "Danny" } 854 | ]; 855 | $scope.example19settings = { 856 | template: '{{option.name}}' 857 | }; 858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 | Setting the field disabled of an option to true will disable that option, if the option was previously 866 | checked it will still stay checked and will not be able to be unchecked. 867 |
868 |
869 |
870 |
871 |

Demo

872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |

The model:

880 |
{{disabledModel|json}}
881 |
882 |
883 |
884 |
885 |

Code

886 |
887 | // HTML 888 |
889 | 890 | // JavaScript 891 | $scope.disabledModel = []; 892 | $scope.disabledData = [ 893 | { id: 1, label: "David", disabled: true}, 894 | { id: 2, label: "Jhon"}, 895 | { id: 3, label: "Danny"} 896 | ]; 897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 | When setting "selectedToTop" to true, selected items will be ordered to the top. When group by is active, the selected items will be at the top of their group. 905 |
906 |
907 |
908 |
909 |

Demo

910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |

The model:

918 |
{{selectedToTopModel|json}}
919 |
920 |
921 |
922 |
923 |

Code

924 |
925 | // HTML 926 |
927 | 928 | // JavaScript 929 | $scope.selectedToTopModel = []; 930 | $scope.selectedToTopData = [ 931 | { id: 1, label: 'David' }, 932 | { id: 2, label: 'Jhon' }, 933 | { id: 3, label: 'Danny' }, 934 | ]; 935 | $scope.selectedToTopSettings = { 936 | selectedToTop: true, 937 | }; 938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 | Example to show that options no longer need to be an object with an id property 946 |
947 |
948 |
949 |
950 |

Demo

951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |

The model:

959 |
{{stringModel|json}}
960 |
961 |
962 |
963 |
964 |

Code

965 |
966 | // HTML 967 |
968 | 969 | $scope.stringModel = []; 970 | $scope.stringData = [ 971 | 'David', 972 | 'Jhon', 973 | 'Danny', 974 | ]; 975 | $scope.stringSettings = { 976 | template: '{{option}}', 977 | smartButtonTextConverter(skip, option) { 978 | return option; 979 | }, 980 | }; 981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 | Example to show that you can replace the button with a custom element. 989 |
990 |
991 |
992 |
993 |

Demo

994 |
995 |
996 | My Custom trigger 997 |
998 |
999 |
1000 |
1001 |

The model:

1002 |
{{transclusionModel|json}}
1003 |
1004 |
1005 |
1006 |
1007 |

Code

1008 |
1009 | // HTML 1010 |
1011 | My Custom trigger 1012 |
1013 | 1014 | $scope.transclusionModel = []; 1015 | $scope.transclusionData = [ 1016 | { id: 1, label: 'David' }, 1017 | { id: 2, label: 'Jhon' }, 1018 | { id: 3, label: 'Danny' }, 1019 | ]; 1020 | $scope.transclusionSettings = { 1021 | }; 1022 |
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 | When idProperty is set the objects will be compared by that property (that should be unique) instead of by reference. 1030 |
1031 |
1032 |
1033 |
1034 |

Demo

1035 |
1036 |
1037 |
1038 |
1039 |
1040 |
1041 |

The model:

1042 |
{{idPropertyModel|json}}
1043 |
1044 |
1045 |
1046 |
1047 |

Code

1048 |
1049 | // HTML 1050 |
1051 |
1052 | 1053 | $scope.idPropertyModel = [{ id: 1 }]; 1054 | $scope.idPropertyData = [ 1055 | { id: 1, label: 'David' }, 1056 | { id: 2, label: 'Jhon' }, 1057 | { id: 3, label: 'Danny' }, 1058 | ]; 1059 | $scope.idPropertySettings = { 1060 | idProperty: 'id', 1061 | }; 1062 |
1063 |
1064 |
1065 |
1066 |
1067 |
1068 |
1069 | When there is a selection this method will be called with the selection as a parameter. The function is supposed to return the text that you want to display on the button. 1070 |
1071 |
1072 |
1073 |
1074 |

Demo

1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 |

The model:

1082 |
{{smartButtonTextProviderModel|json}}
1083 |
1084 |
1085 |
1086 |
1087 |

Code

1088 |
1089 | // HTML 1090 |
1091 |
1092 | 1093 | $scope.smartButtonTextProviderModel = []; 1094 | $scope.smartButtonTextProviderData = [ 1095 | { id: 1, label: 'David' }, 1096 | { id: 2, label: 'Jhon' }, 1097 | { id: 3, label: 'Danny' }, 1098 | ]; 1099 | $scope.idPropertySettings = { 1100 | smartButtonTextProvider(selectionArray) { 1101 | return selectionArray.length + 2; 1102 | }, 1103 | }; 1104 |
1105 |
1106 |
1107 |
1108 |
1109 |

Full API Documentation

1110 |

Attributes

1111 |

List of allowed attributes, you can find more information about them in the usage examples above.

1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1125 | 1126 | 1127 | 1128 | 1129 | 1132 | 1133 | 1134 | 1135 | 1136 | 1139 | 1140 | 1141 | 1142 | 1143 | 1146 | 1147 | 1148 | 1149 | 1150 | 1153 | 1154 | 1155 | 1156 | 1157 | 1160 | 1161 | 1162 | 1163 | 1164 | 1167 | 1168 | 1169 | 1170 | 1171 |
Attribute NameTypeDescription
1123 | selected-model 1124 | Object / ArrayThe object the will contain the model for the selected items in the dropdown.
1130 | options 1131 | Object / ArrayThe options for the dropdown.
1137 | extra-settings 1138 | ObjectThe settings for the directive, more information about these settings are available below.
1144 | events 1145 | ObjectEvents callbacks, more information below.
1151 | translation-texts 1152 | ObjectGives the ability to modify the default texts in the directive. More information below.
1158 | search-filter 1159 | StringUses for settings the search filter from outside the direcrtive.
1165 | disabled 1166 | BooleanUsed for disabling the dropdown.
1172 |

Settings

1173 |

1174 | Available settings that effects the display or behavior of the directive. 1175 |
These setting are set with the "extra-settings" attribute. 1176 |

1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1339 | 1340 | 1341 | 1344 | 1345 | 1346 | 1349 | 1350 | 1351 | 1354 | 1355 | 1356 |
Property NameTypeDefault ValueDescription
dynamicTitleBooleantrueIndicates if the text of the button should change when selecting items from the list.
closeOnBlurBooleantrueIndicates if the dropdown should close when clicking outside of it's scope.
displayPropStringlabelThe name of the property that contains the text for the item.
enableSearchBooleanfalseIndicated if to show the search input or not.
clearSearchOnCloseBooleanfalseIndicated if to clear the search field when the dropdown has closed.
searchFieldString"$"Indicates on which field the search should be done
selectionLimitNumber0The max allowed selected items for the list. For more information see the examples above.
showCheckAllBooleantrueIndicates if to show the "Check All" item.
showUncheckAllBooleantrueIndicates if to show the "Uncheck All" item.
showEnableSearchButtonBooleanfalseIndicates if to show the "Enable search / Disable search" item.
closeOnSelectBooleanfalseIndicates if to close the dropdown after checking an item on the list.
closeOnDeselectBooleanfalseIndicates if to close the dropdown after unchecking an item on the list. With selectionLimit = 1 setting this to true does the same as setting closeOnSelect to true.
buttonClassesStringbtn btn-defaultThe CSS classes that used for setting the style of the button.
1267 | groupBy 1268 | StringundefinedThe name of the property which you like to group by your options. See grouping example.
groupByTextProviderFunctionangular.noopA callback to a function that provide that name for each group when using groupBy setting. The parameter for the function will be the value of the groupBy property.
scrollableBooleanfalseIndicates if the dropdown is scrollable, useful if you have a lot of items.
scrollableHeightNumber300pxIndicates the height of the drop down if the dropdown is scrollable.
smartButtonMaxItemsNumber0Manages the "Smart Button Text" feature, defines the maximum amount of items to on the button.
smartButtonTextConverterFunctionangular.noopRelated the "Smart Button Text" feature, if a function provided - it will called with two paramters: The item's text and the original item, the return value will displayed instead of the item's display property. This feature is useful when you want to convert the displayed text into something else.
styleActiveBooleanfalseIndicates if the list items should get a class active applied when they are selected.
keyboardControlsBooleanfalseWhen activated the dropdown can be used with the keyboard instead of with the mouse.
templateString{ {getPropertyForObject(option, settings.displayProp)} }Can be used to modify the appearance of an option in the list, each option is accessible as option.
selectByGroupsArrayundefinedValues of the groupby property that you want to be selectable as group
1329 | checkBoxes 1330 | BooleanfalseIndicated if to show a normal dropdown with glyphicons or HTML checkboxes.
1337 | selectedToTop 1338 | Booleanfalse 1342 | When true will put the selected options at the top of the list 1343 |
1347 | idProperty 1348 | stringundefined 1352 | Used to compare by property instead of by reference. 1353 |
1357 |

Events

1358 |

Available event callbacks what the directive fires. These callbacks are set with "events" attribute.

1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 |
Event NameParametersDescription
onItemSelectitemFired when selecting an item.
onItemDeselectitemFired when unselecting an item.
onSelectAllFired when clicking select all.
onDeselectAllFired when clicking unselect all.
onInitDoneFired when the directive done with the "link" phase.
onMaxSelectionReachedFired when the user reaches the max allowed selected items.
onSelectionChangedFired when the selection changes.
1405 |

Translation Texts

1406 |

Available texts that you can override if you wan't to make a translation for your website. These are set with the "translation-texts" attribute.

1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | 1415 | 1416 | 1417 | 1418 | 1419 | 1420 | 1421 | 1422 | 1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 |
Property NameDefault ValueDescription
checkAllCheck All"Check All" item's text.
uncheckAllUncheck All"Uncheck All" item's text.
enableSearchEnable search"enable search" item's text.
disableSearchDisable search"disable search" item's text.
selectionCountcheckedThe suffix for "X/Y" that showed when using selection limit.
selectionOf/The value between the selected values and the max values when using selection limit.
searchPlaceholderSearch...The placeholder for the search input.
buttonDefaultTextSelectThe default text that used for the button when no items selected.
dynamicButtonTextSuffixcheckedThe suffix for the button that used when using "dynamicText".
selectGroupSelect All:The prefix of the group selection.
1468 |
1469 | -------------------------------------------------------------------------------- /src/app/main/pygment_trac.scss: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kn { font-weight: bold } /* Keyword.Namespace */ 25 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 26 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 27 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 28 | .highlight .m { color: #009999 } /* Literal.Number */ 29 | .highlight .s { color: #d14 } /* Literal.String */ 30 | .highlight .na { color: #008080 } /* Name.Attribute */ 31 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 32 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 33 | .highlight .no { color: #008080 } /* Name.Constant */ 34 | .highlight .ni { color: #800080 } /* Name.Entity */ 35 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 37 | .highlight .nn { color: #555555 } /* Name.Namespace */ 38 | .highlight .nt { color: #000080 } /* Name.Tag */ 39 | .highlight .nv { color: #008080 } /* Name.Variable */ 40 | .highlight .ow { font-weight: bold } /* Operator.Word */ 41 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 43 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 44 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 45 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 46 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 47 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 48 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 49 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 50 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 51 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 52 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 53 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 54 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 55 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 56 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 57 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 58 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 59 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 60 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 61 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 62 | 63 | .type-csharp .highlight .k { color: #0000FF } 64 | .type-csharp .highlight .kt { color: #0000FF } 65 | .type-csharp .highlight .nf { color: #000000; font-weight: normal } 66 | .type-csharp .highlight .nc { color: #2B91AF } 67 | .type-csharp .highlight .nn { color: #000000 } 68 | .type-csharp .highlight .s { color: #A31515 } 69 | .type-csharp .highlight .sc { color: #A31515 } 70 | -------------------------------------------------------------------------------- /src/app/main/stylesheet.scss: -------------------------------------------------------------------------------- 1 | /* HTML5 display-role reset for older browsers */ 2 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 3 | display: block; 4 | } 5 | body { 6 | line-height: 1; 7 | } 8 | ol, ul { 9 | list-style: none; 10 | } 11 | blockquote, q { 12 | quotes: none; 13 | } 14 | blockquote:before, blockquote:after, q:before, q:after { 15 | content:''; 16 | content: none; 17 | } 18 | table { 19 | border-collapse: collapse; 20 | border-spacing: 0; 21 | } 22 | /* LAYOUT STYLES */ 23 | body { 24 | font-size: 15px; 25 | line-height: 1.5; 26 | background: #fafafa url(../assets/body-bg.jpg) 0 0 repeat; 27 | font-family:'Helvetica Neue', Helvetica, Arial, serif; 28 | font-weight: 400; 29 | color: #666; 30 | } 31 | a { 32 | color: #2879d0; 33 | } 34 | a:hover { 35 | color: #2268b2; 36 | } 37 | header { 38 | padding-top: 40px; 39 | padding-bottom: 40px; 40 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 41 | background: #2e7bcf url(../assets/header-bg.jpg) 0 0 repeat-x; 42 | border-bottom: solid 1px #275da1; 43 | height: auto; 44 | margin-bottom: 10px; 45 | } 46 | header h1 { 47 | letter-spacing: -1px; 48 | font-size: 72px; 49 | color: #fff; 50 | line-height: 1; 51 | margin-bottom: 0.2em; 52 | width: auto; 53 | } 54 | header h2 { 55 | font-size: 26px; 56 | color: #9ddcff; 57 | font-weight: normal; 58 | line-height: 1.3; 59 | width: 540px; 60 | letter-spacing: 0; 61 | } 62 | .inner { 63 | position: relative; 64 | width: 1170px; 65 | margin: 0 auto; 66 | padding-left: 30px; 67 | padding-right: 30px; 68 | } 69 | #content-wrapper { 70 | border-top: solid 1px #fff; 71 | padding-top: 30px; 72 | } 73 | #main-content { 74 | width: 690px; 75 | float: left; 76 | } 77 | #main-content img { 78 | max-width: 100%; 79 | } 80 | aside#sidebar { 81 | width: 200px; 82 | padding-left: 20px; 83 | min-height: 504px; 84 | float: right; 85 | background: transparent url(../assets/sidebar-bg.jpg) 0 0 no-repeat; 86 | font-size: 12px; 87 | line-height: 1.3; 88 | } 89 | aside#sidebar p.repo-owner, aside#sidebar p.repo-owner a { 90 | font-weight: bold; 91 | } 92 | #downloads { 93 | margin-bottom: 40px; 94 | } 95 | a.gh-button { 96 | width: 134px; 97 | height: 58px; 98 | line-height: 1.2; 99 | font-size: 23px; 100 | color: #fff; 101 | padding-left: 68px; 102 | padding-top: 22px; 103 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 104 | } 105 | a.gh-button small { 106 | display: block; 107 | font-size: 11px; 108 | } 109 | header a.gh-button { 110 | position: absolute; 111 | right: 0; 112 | top: 0; 113 | background: transparent url(../assets/github-button.png) 0 0 no-repeat; 114 | } 115 | aside a.gh-button { 116 | width: 138px; 117 | padding-left: 64px; 118 | display: block; 119 | background: transparent url(../assets/download-button.png) 0 0 no-repeat; 120 | margin-bottom: 20px; 121 | font-size: 21px; 122 | } 123 | code, pre { 124 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 125 | color: #222; 126 | margin-bottom: 30px; 127 | font-size: 13px; 128 | } 129 | code { 130 | background-color: #f2f8fc; 131 | border: solid 1px #dbe7f3; 132 | padding: 0 3px; 133 | } 134 | pre { 135 | padding: 20px; 136 | background: #fff; 137 | text-shadow: none; 138 | overflow: auto; 139 | border: solid 1px #f2f2f2; 140 | } 141 | pre code { 142 | color: #2879d0; 143 | background-color: #fff; 144 | border: none; 145 | padding: 0; 146 | } 147 | ul, ol, dl { 148 | margin-bottom: 20px; 149 | } 150 | /* COMMON STYLES */ 151 | hr { 152 | height: 1px; 153 | line-height: 1px; 154 | margin-top: 1em; 155 | padding-bottom: 1em; 156 | border: none; 157 | } 158 | table { 159 | width: 100%; 160 | border: 1px solid #ebebeb; 161 | } 162 | th { 163 | font-weight: 500; 164 | } 165 | td { 166 | border: 1px solid #ebebeb; 167 | text-align: center; 168 | font-weight: 300; 169 | } 170 | form { 171 | background: #f2f2f2; 172 | padding: 20px; 173 | } 174 | /* GENERAL ELEMENT TYPE STYLES */ 175 | #main-content h1 { 176 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 177 | font-size: 2.8em; 178 | letter-spacing: -1px; 179 | color: #474747; 180 | } 181 | #main-content h1:before { 182 | content:"/"; 183 | color: #9ddcff; 184 | padding-right: 0.3em; 185 | margin-left: -0.9em; 186 | } 187 | #main-content h2 { 188 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 189 | font-size: 22px; 190 | font-weight: bold; 191 | margin-bottom: 8px; 192 | color: #474747; 193 | } 194 | #main-content h2:before { 195 | content:"//"; 196 | color: #9ddcff; 197 | padding-right: 0.3em; 198 | margin-left: -1.5em; 199 | } 200 | #main-content h3 { 201 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 202 | font-size: 18px; 203 | font-weight: bold; 204 | margin-top: 24px; 205 | margin-bottom: 8px; 206 | color: #474747; 207 | } 208 | #main-content h3:before { 209 | content:"///"; 210 | color: #9ddcff; 211 | padding-right: 0.3em; 212 | margin-left: -2em; 213 | } 214 | #main-content h4 { 215 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 216 | font-size: 15px; 217 | font-weight: bold; 218 | color: #474747; 219 | } 220 | h4:before { 221 | content:"////"; 222 | color: #9ddcff; 223 | padding-right: 0.3em; 224 | } 225 | #main-content h5 { 226 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 227 | font-size: 14px; 228 | color: #474747; 229 | } 230 | h5:before { 231 | content:"/////"; 232 | color: #9ddcff; 233 | padding-right: 0.3em; 234 | margin-left: -3.2em; 235 | } 236 | #main-content h6 { 237 | font-family:'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 238 | font-size: .8em; 239 | color: #474747; 240 | } 241 | h6:before { 242 | content:"//////"; 243 | color: #9ddcff; 244 | padding-right: 0.3em; 245 | margin-left: -3.7em; 246 | } 247 | p { 248 | margin-bottom: 20px; 249 | } 250 | a { 251 | text-decoration: none; 252 | } 253 | p a { 254 | font-weight: 400; 255 | } 256 | blockquote { 257 | font-size: 1.6em; 258 | border-left: 10px solid #e9e9e9; 259 | margin-bottom: 20px; 260 | padding: 0 0 0 30px; 261 | } 262 | ul { 263 | list-style: disc inside; 264 | padding-left: 20px; 265 | } 266 | ol { 267 | list-style: decimal inside; 268 | padding-left: 3px; 269 | } 270 | dl dd { 271 | font-style: italic; 272 | font-weight: 100; 273 | } 274 | footer { 275 | margin-top: 40px; 276 | padding-top: 20px; 277 | padding-bottom: 10px; 278 | font-size: 13px; 279 | color: #aaa; 280 | } 281 | footer a { 282 | color: #666; 283 | } 284 | footer a:hover { 285 | color: #444; 286 | } 287 | /* MISC */ 288 | .clearfix:after { 289 | clear: both; 290 | content:'.'; 291 | display: block; 292 | visibility: hidden; 293 | height: 0; 294 | } 295 | .clearfix { 296 | display: inline-block; 297 | } 298 | * html .clearfix { 299 | height: 1%; 300 | } 301 | .clearfix { 302 | display: block; 303 | } 304 | /* #Media Queries 305 | ================================================== */ 306 | 307 | /* Smaller than standard 960 (devices and browsers) */ 308 | @media only screen and (max-width: 959px) { 309 | } 310 | /* Tablet Portrait size to standard 960 (devices and browsers) */ 311 | @media only screen and (min-width: 768px) and (max-width: 959px) { 312 | .inner { 313 | width: 740px; 314 | } 315 | header h1, header h2 { 316 | width: 740px; 317 | } 318 | header h1 { 319 | font-size: 60px; 320 | } 321 | header h2 { 322 | font-size: 30px; 323 | } 324 | #main-content { 325 | width: 490px; 326 | } 327 | #main-content h1:before, #main-content h2:before, #main-content h3:before, #main-content h4:before, #main-content h5:before, #main-content h6:before { 328 | content: none; 329 | padding-right: 0; 330 | margin-left: 0; 331 | } 332 | } 333 | /* All Mobile Sizes (devices and browser) */ 334 | @media only screen and (max-width: 767px) { 335 | .inner { 336 | width: 93%; 337 | } 338 | header { 339 | padding: 20px 0; 340 | } 341 | header .inner { 342 | position: relative; 343 | } 344 | header h1, header h2 { 345 | width: 100%; 346 | } 347 | header h1 { 348 | font-size: 48px; 349 | } 350 | header h2 { 351 | font-size: 24px; 352 | } 353 | header a.gh-button { 354 | background-image: none; 355 | width: auto; 356 | height: auto; 357 | display: inline-block; 358 | margin-top: 15px; 359 | padding: 5px 10px; 360 | position: relative; 361 | text-align: center; 362 | font-size: 13px; 363 | line-height: 1; 364 | background-color: #9ddcff; 365 | color: #2879d0; 366 | -moz-border-radius: 5px; 367 | -webkit-border-radius: 5px; 368 | border-radius: 5px; 369 | } 370 | header a.gh-button small { 371 | font-size: 13px; 372 | display: inline; 373 | } 374 | #main-content, aside#sidebar { 375 | float: none; 376 | width: 100% ! important; 377 | } 378 | aside#sidebar { 379 | background-image: none; 380 | margin-top: 20px; 381 | border-top: solid 1px #ddd; 382 | padding: 20px 0; 383 | min-height: 0; 384 | } 385 | aside#sidebar a.gh-button { 386 | display: none; 387 | } 388 | #main-content h1:before, #main-content h2:before, #main-content h3:before, #main-content h4:before, #main-content h5:before, #main-content h6:before { 389 | content: none; 390 | padding-right: 0; 391 | margin-left: 0; 392 | } 393 | 394 | a.option[disabled] { 395 | opacity: 0.5; 396 | } 397 | } 398 | 399 | .custom-trigger { 400 | padding: 0.75em; 401 | margin-top: 1.5em; 402 | border: 1px solid #ccc; 403 | cursor: pointer; 404 | } 405 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ 406 | @media only screen and (min-width: 480px) and (max-width: 767px) { 407 | } 408 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ 409 | @media only screen and (max-width: 479px) { 410 | } 411 | -------------------------------------------------------------------------------- /src/app/v1docs/v1docs.component.js: -------------------------------------------------------------------------------- 1 | export default function v1Component() { 2 | const component = { 3 | templateUrl: 'app/v1docs/v1docs.template.html', 4 | }; 5 | 6 | return component; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/v1docs/v1docs.template.html: -------------------------------------------------------------------------------- 1 | Main docs 2 |

Full V1 API Documentation

3 |

Attributes

4 |

List of allowed attributes, you can find more information about them in the usage examples above.

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 60 | 61 | 62 | 63 | 64 | 67 | 68 | 69 | 70 | 71 | 74 | 75 | 76 | 77 | 78 |
Attribute NameTypeDescription
16 | selected-model 17 | Object / ArrayThe object the will contain the model for the selected items in the dropdown.
23 | options 24 | Object / ArrayThe options for the dropdown.
30 | extra-settings 31 | ObjectThe settings for the directive, more information about these settings are available below.
37 | events 38 | ObjectEvents callbacks, more information below.
44 | translation-texts 45 | ObjectGives the ability to modify the default texts in the directive. More information below.
51 | group-by 52 | StringThe name of the property which you like to group by your options. See grouping example.
58 | checkboxes 59 | BooleanIndicated if to show a normal dropdown with glyphicons or HTML checkboxes.
65 | search-filter 66 | StringUses for settings the search filter from outside the direcrtive.
72 | disabled 73 | BooleanUsed for disabling the dropdown.
79 |

Settings

80 |

81 | Available settings that effects the display or behavior of the directive. 82 |
These setting are set with the "extra-settings" attribute. 83 |

84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 |
Property NameTypeDefault ValueDescription
dynamicTitleBooleantrueIndicates if the text of the button should change when selecting items from the list.
closeOnBlurBooleantrueIndicates if the dropdown should close when clicking outside of it's scope.
displayPropStringlabelThe name of the property that contains the text for the item.
idPropStringidThe name of the property that contains the id for the elements.
externalIdPropStringidThe name of the property that will use for the selected items model.
enableSearchBooleanfalseIndicated if to show the search input or not.
clearSearchOnCloseBooleanfalseIndicated if to clear the search field when the dropdown has closed.
searchFieldString"$"Indicates on which field the search should be done
selectionLimitNumber0The max allowed selected items for the list. For more information see the examples above.
showCheckAllBooleantrueIndicates if to show the "Check All" item.
showUncheckAllBooleantrueIndicates if to show the "Uncheck All" item.
showEnableSearchButtonBooleanfalseIndicates if to show the "Enable search / Disable search" item.
closeOnSelectBooleanfalseIndicates if to close the dropdown after checking an item on the list.
closeOnDeselectBooleanfalseIndicates if to close the dropdown after unchecking an item on the list. With selectionLimit = 1 setting this to true does the same as setting closeOnSelect to true.
buttonClassesStringbtn btn-defaultThe CSS classes that used for setting the style of the button.
groupByTextProviderFunctionangular.noopA callback to a function that provide that name for each group when using group-by attribute. The parameter for the function will be the value of the group-by property.
scrollableBooleanfalseIndicates if the dropdown is scrollable, useful if you have a lot of items.
scrollableHeightNumber300pxIndicates the height of the drop down if the dropdown is scrollable.
smartButtonMaxItemsNumber0Manages the "Smart Button Text" feature, defines the maximum amount of items to on the button.
smartButtonTextConverterFunctionangular.noopRelated the "Smart Button Text" feature, if a function provided - it will called with two paramters: The item's text and the original item, the return value will displayed instead of the item's display property. This feature is useful when you want to convert the displayed text into something else.
styleActiveBooleanfalseIndicates if the list items should get a class active applied when they are selected.
keyboardControlsBooleanfalseWhen activated the dropdown can be used with the keyboard instead of with the mouse.
templateString { {getPropertyForObject(option, settings.displayProp)} }Can be used to modify the appearance of an option in the list, each option is accessible as option.
selectByGroupsArrayundefinedValues of the groupby property that you want to be selectable as group
240 |

Events

241 |

Available event callbacks what the directive fires. These callbacks are set with "events" attribute.

242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 |
Event NameParametersDescription
onItemSelectitemFired when selecting an item.
onItemDeselectitemFired when unselecting an item.
onSelectAllFired when clicking select all.
onDeselectAllFired when clicking unselect all.
onInitDoneFired when the directive done with the "link" phase.
onMaxSelectionReachedFired when the user reaches the max allowed selected items.
onSelectionChangedFired when the selection changes.
288 |

Translation Texts

289 |

Available texts that you can override if you wan't to make a translation for your website. These are set with the "translation-texts" attribute.

290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 |
Property NameDefault ValueDescription
checkAllCheck All"Check All" item's text.
uncheckAllUncheck All"Uncheck All" item's text.
enableSearchEnable search"enable search" item's text.
disableSearchDisable search"disable search" item's text.
selectionCountcheckedThe suffix for "X/Y" that showed when using selection limit.
selectionOf/The value between the selected values and the max values when using selection limit.
searchPlaceholderSearch...The placeholder for the search input.
buttonDefaultTextSelectThe default text that used for the button when no items selected.
dynamicButtonTextSuffixcheckedThe suffix for the button that used when using "dynamicText".
selectGroupSelect All:The prefix of the group selection.
351 | -------------------------------------------------------------------------------- /src/assets/body-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/src/assets/body-bg.jpg -------------------------------------------------------------------------------- /src/assets/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/src/assets/download-button.png -------------------------------------------------------------------------------- /src/assets/github-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/src/assets/github-button.png -------------------------------------------------------------------------------- /src/assets/header-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/src/assets/header-bg.jpg -------------------------------------------------------------------------------- /src/assets/highlight-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/src/assets/highlight-bg.jpg -------------------------------------------------------------------------------- /src/assets/sidebar-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotansimha/angularjs-dropdown-multiselect/e73fca5f5279155cd583d965f4599debae60a5f8/src/assets/sidebar-bg.jpg -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularJS Dropdown Multiselect 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 |
39 |
40 | 41 | 42 | View project on 43 |
GitHub 44 |
45 |
46 |

AngularJS Dropdown Multiselect

47 |

based on Bootstrap's dropdown

48 |
49 |
50 |
51 |
52 |
53 | 54 |
55 |
56 |
57 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | --------------------------------------------------------------------------------