├── .bowerrc ├── .gitignore ├── README.rst ├── bower.json ├── dist ├── ionic-multiselect.js ├── ionic-multiselect.min.js └── templates │ ├── item-template.html │ └── modal-template.html ├── example ├── controller.main.js ├── index.html └── lib │ └── ionic │ ├── css │ ├── ionic.css │ └── ionic.min.css │ ├── fonts │ ├── ionicons.eot │ ├── ionicons.svg │ ├── ionicons.ttf │ └── ionicons.woff │ ├── js │ ├── angular-ui │ │ ├── angular-ui-router.js │ │ └── angular-ui-router.min.js │ ├── angular │ │ ├── angular-animate.js │ │ ├── angular-animate.min.js │ │ ├── angular-resource.js │ │ ├── angular-resource.min.js │ │ ├── angular-sanitize.js │ │ ├── angular-sanitize.min.js │ │ ├── angular.js │ │ └── angular.min.js │ ├── ionic-angular.js │ ├── ionic-angular.min.js │ ├── ionic.bundle.js │ ├── ionic.bundle.min.js │ ├── ionic.js │ └── ionic.min.js │ ├── scss │ ├── _action-sheet.scss │ ├── _animations.scss │ ├── _backdrop.scss │ ├── _badge.scss │ ├── _bar.scss │ ├── _button-bar.scss │ ├── _button.scss │ ├── _checkbox.scss │ ├── _form.scss │ ├── _grid.scss │ ├── _items.scss │ ├── _list.scss │ ├── _loading.scss │ ├── _menu.scss │ ├── _mixins.scss │ ├── _modal.scss │ ├── _platform.scss │ ├── _popover.scss │ ├── _popup.scss │ ├── _progress.scss │ ├── _radio.scss │ ├── _range.scss │ ├── _refresher.scss │ ├── _reset.scss │ ├── _scaffolding.scss │ ├── _select.scss │ ├── _slide-box.scss │ ├── _spinner.scss │ ├── _tabs.scss │ ├── _toggle.scss │ ├── _transitions.scss │ ├── _type.scss │ ├── _util.scss │ ├── _variables.scss │ ├── ionic.scss │ └── ionicons │ │ ├── _ionicons-font.scss │ │ ├── _ionicons-icons.scss │ │ ├── _ionicons-variables.scss │ │ └── ionicons.scss │ └── version.json ├── gulpfile.js └── package.json /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "json": "bower.json" 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | example/bower_components -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Ionic Multiselect 2 | =================== 3 | 4 | **THIS REPO IS DEPRECATED.** Multiselect for Inonic Framework. Inspired by ionic-fancy-select and this snippet: http://codepen.io/mhartington/pen/CImqy?editors=101. 5 | 6 | Install 7 | ------- 8 | 9 | Via bower:: 10 | 11 | bower install ionic-multiselect 12 | 13 | Getting started 14 | --------------- 15 | 16 | 1. Add script js:: 17 | 18 | 19 | 20 | 21 | 2. Add the module **ionic-multiselect** to module main:: 22 | 23 | var App = angular.module("MainApp", ["ionic-multiselect"]); 24 | 25 | 3. Configure module:: 26 | 27 | App.config(function(multiselectProvider) { 28 | multiselectProvider.setTemplateUrl('bower_components/ionic-multiselect/dist/templates/item-template.html'); 29 | multiselectProvider.setModalTemplateUrl('bower_components/ionic-multiselect/dist/templates/modal-template.html'); 30 | }); 31 | 32 | 4. Add to html this line:: 33 | 34 | 39 | 40 | 41 | #or 42 | 43 | 57 | 58 | 59 | 5. Get value selected:: 60 | 61 | //Your controller 62 | $scope.onValueChanged = function(value){ 63 | //Value return a array objects with items selected 64 | console.log(value); 65 | } 66 | 67 | Attributes 68 | ---------- 69 | 70 | 1. header-text 71 | 72 | Type: String 73 | Used to specify the text that is shown in the Modal's header bar. 74 | 75 | 2. Items 76 | 77 | Type: Array 78 | A list of items that is bound to the select. 79 | 80 | 3- text-property 81 | 82 | Type: String 83 | Property description of item the array. 84 | 85 | 4. value-property 86 | 87 | Type: String 88 | Property id of item the array. 89 | 90 | 5. Is-Translate 91 | 92 | type: Boolean 93 | If used angular translate for item text. 94 | 95 | 6. Index-translate 96 | 97 | type: String 98 | If used angular-translate this is the tag for indicate el tag main for items. For example, if we need to show the categories used the tag 'CATEGORY_' and ionic-multiselect automatically search the following internally in the ng-repeat 'CATEGORY_1' 'CATEGORY_2', etc. Internally uses the value-property field. 99 | 100 | 7. text 101 | 102 | Type: String 103 | Value default multiselect. 104 | 105 | 8. modal-template-url 106 | 107 | Type: URL 108 | An optional URL that can be used to customise the look and feel of the Modal 109 | 110 | 9. template-url 111 | 112 | Type: URL 113 | An optional URL that can be used to custome the look and feel of fancy-select element. 114 | 115 | 10. note-text 116 | 117 | Type: String 118 | An optional note that can be displayed in the default multiselect element. 119 | 120 | 11. value-changed (Callback) 121 | 122 | Parameters: value - The currently selected value or list of values 123 | Raised when the current value changes. 124 | 125 | 12. default-value 126 | 127 | Type: Array 128 | A list of values (from the value-property) that is default to the select 129 | 130 | Example 131 | ------- 132 | 133 | Check the file `index`_. 134 | 135 | .. _index: https://github.com/mapeveri/ionic-multiselect/blob/master/example/index.html 136 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-multiselect", 3 | "version": "0.1.8", 4 | "authors": [ 5 | "Martin Peveri " 6 | ], 7 | "description": "Multiselect for Inonic Framework.", 8 | "main": "./dist/ionic-multiselect.js", 9 | "moduleType": [], 10 | "keywords": [ 11 | "angular", 12 | "angularjs", 13 | "javascript", 14 | "ionic", 15 | "Multiselect" 16 | ], 17 | "license": "MIT", 18 | "homepage": "https://github.com/mapeveri/ionic-multiselect", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests", 25 | "images", 26 | "example" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /dist/ionic-multiselect.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("ionic-multiselect", []) 5 | .filter('translateItem', ["$injector", "$parse", function($injector, $parse) { 6 | /** 7 | * @name translateItem 8 | * @desc Translate value item modal in base to value_property 9 | * @param {Object} item: Object data item 10 | * @returns {String} 11 | */ 12 | return function(item, scope) { 13 | 14 | var filterTranslate; 15 | try{ 16 | var filterTranslate = $injector.get('$filter'); 17 | //Parse item property of the object 18 | var parseFun = $parse('item.' + scope.valueProperty); 19 | var valueTranslate = parseFun(scope); 20 | return filterTranslate('translate')(scope.indexTranslate + valueTranslate); 21 | }catch(e){ 22 | return ""; 23 | } 24 | }; 25 | }]) 26 | .filter('showTextData', ["$injector", function($injector) { 27 | /** 28 | * @name showTextData 29 | * @desc Filter that show data text 30 | * @param {String} value: Value text show 31 | * @returns {Array} 32 | */ 33 | return function(value, scope) { 34 | 35 | var filterTranslate; 36 | try{ 37 | var filterTranslate = $injector.get('$filter'); 38 | }catch(e){} 39 | 40 | var arr = []; 41 | if(value.indexOf("^") > -1){ 42 | arr = value.split("^"); 43 | arr = arr.filter(Boolean); 44 | var tot = arr.length; 45 | 46 | for(var i=0;i 96 | * 97 | */ 98 | .directive("multiselect", ["$ionicModal", "multiselect", function($ionicModal, multiselect) { 99 | return { 100 | restrict: "E", 101 | //Template with item for show modal 102 | template: function(element, attrs) { 103 | if (attrs.templateUrl || multiselect.templateUrl) { 104 | return ""; 105 | } else { 106 | return ''; 107 | } 108 | }, 109 | //Attributes 110 | scope: { 111 | items: "=", // Needs to have a values 112 | defaultValue: "=", // Needs to have a default values selected 113 | valueChangedCallback: "&valueChanged", // The callback used to signal that the value has changed 114 | getCustomTextCallback: "&getCustomText" // The callback used to get custom text based on the selected value 115 | }, 116 | //Conected directive 117 | link: function(scope, element, attrs) { 118 | // Header usado en ion-header-bar 119 | scope.headerText = attrs.headerText || ''; 120 | // Text displayed on label 121 | scope.text = attrs.text || ''; 122 | scope.defaultText = attrs.text || ''; 123 | // Data binding properties 124 | scope.checkedProperty = attrs.checkedProperty || "checked"; 125 | scope.textProperty = attrs.textProperty || "text"; 126 | scope.valueProperty = attrs.valueProperty || "id"; 127 | //Translate properties 128 | scope.isTranslate = (attrs.isTranslate === "true") || false; 129 | scope.indexTranslate = attrs.indexTranslate || ""; 130 | // The modal properties 131 | scope.modalTemplateUrl = attrs.modalTemplateUrl || multiselect.modalTemplateUrl; 132 | scope.modalAnimation = attrs.modalAnimation; 133 | // Note properties 134 | scope.noteText = attrs.noteText || ""; 135 | 136 | //Init modal with the items 137 | if (scope.modalTemplateUrl) { 138 | $ionicModal.fromTemplateUrl( 139 | scope.modalTemplateUrl, 140 | { 141 | scope: scope, 142 | animation: scope.modalAnimation 143 | } 144 | ).then(function(modal) { 145 | scope.modal = modal; 146 | }); 147 | } else { 148 | scope.modal = $ionicModal.fromTemplate('', 149 | { 150 | scope: scope, 151 | animation: scope.modalAnimation 152 | } 153 | ); 154 | } 155 | 156 | //Remove modal 157 | scope.$on("$destroy", function() { 158 | scope.modal.remove(); 159 | }); 160 | 161 | /** 162 | * @name getItemText 163 | * @desc Get text property of objeto 164 | * @param {Object} item: Object data item 165 | * @returns {String} 166 | */ 167 | scope.getItemText = function(item) { 168 | return scope.textProperty ? item[scope.textProperty] : item; 169 | }; 170 | 171 | /** 172 | * @name getItemValue 173 | * @desc Get value property of objet 174 | * @param {Object} item: Object data item 175 | * @returns {String} 176 | */ 177 | scope.getItemValue = function(item) { 178 | return scope.valueProperty ? item[scope.valueProperty] : item; 179 | }; 180 | 181 | /** 182 | * @name getText 183 | * @desc Get items selected 184 | * @param {Array} value: Array with values showed in modal 185 | * @returns {String} 186 | */ 187 | scope.getText = function(value) { 188 | // Push the values into a temporary array so that they can be iterated through 189 | var temp = value ? value : []; 190 | 191 | var text = ""; 192 | if (temp.length) { 193 | //Concatenate the items 194 | angular.forEach(scope.items, function(item, key) { 195 | for (var i = 0; i < temp.length; i++) { 196 | if (scope.getItemValue(item) == temp[i]) { 197 | //if is translate 198 | if(scope.isTranslate){ 199 | text += (text.length ? "^" : "") + scope.getItemValue(item); 200 | }else{ 201 | text += (text.length ? "^" : "") + scope.getItemText(item); 202 | } 203 | break; 204 | } 205 | } 206 | }); 207 | }else{ 208 | //Text default (When is translate) 209 | text = scope.defaultText; 210 | } 211 | 212 | //Text default when not select nothing and not is translate 213 | if (!text.length && !scope.isTranslate) { 214 | text = scope.defaultText; 215 | } 216 | 217 | //Check if empty 218 | if(scope.isTranslate){ 219 | if(text.trim() == ""){ 220 | text = "^"; 221 | } 222 | } 223 | 224 | // If a callback has been specified for the text 225 | return scope.getCustomTextCallback({value: value}) || text; 226 | }; 227 | 228 | /** 229 | * @name hideItems 230 | * @desc Hide modal 231 | * @param {Object} event: Event js 232 | */ 233 | scope.hideItems = function(event) { 234 | scope.modal.hide(); 235 | }; 236 | 237 | /** 238 | * @name onCheckValueChanged 239 | * @desc Raised by watch when the check value changes 240 | * @param {Object} newValue: New value object 241 | * @param {Object} oldValue: Old value object 242 | */ 243 | scope.onCheckValueChanged = function(newValue, oldValue) { 244 | if(typeof(newValue) !== "undefined"){ 245 | // Notify subscribers that the value has changed 246 | scope.valueChangedCallback({value: newValue}); 247 | } 248 | }; 249 | 250 | /** 251 | * @name onValueChanged 252 | * @desc Raised by watch when the value changes 253 | * @param {Object} newValue: New value object 254 | * @param {Object} oldValue: Old value object 255 | */ 256 | scope.onValueChanged = function(newValue, oldValue) { 257 | scope.text = scope.getText(newValue); 258 | }; 259 | 260 | /** 261 | * @name showItems 262 | * @desc Show modal 263 | * @param {Object} event: Event js 264 | */ 265 | scope.showItems = function(event) { 266 | event.preventDefault(); // Prevent the event from bubbling 267 | scope.modal.show(); 268 | }; 269 | 270 | /** 271 | * @name validate 272 | * @desc Validates the current list 273 | */ 274 | scope.validate = function() { 275 | scope.fetchCheckedItems(); 276 | scope.hideItems(); 277 | }; 278 | 279 | /** 280 | * @name fetchCheckedItems 281 | * @desc parses the items array and determines which items are checked 282 | */ 283 | scope.fetchCheckedItems = function() { 284 | scope.value = []; 285 | if (scope.items) { 286 | var arrChecked = []; 287 | angular.forEach(scope.items, function(item, key) { 288 | if (item[scope.checkedProperty]) { 289 | scope.value[key] = scope.getItemValue(item); 290 | arrChecked.push(item); 291 | }else{ 292 | scope.value[key] = ""; 293 | } 294 | }); 295 | 296 | scope.itemChecked = arrChecked; 297 | } 298 | } 299 | 300 | // Update scope.items checked attribute with scope.defaultValue 301 | scope.fetchCheckedDefaultItems = function() { 302 | scope.value = []; 303 | if (scope.items) { 304 | var arrChecked = []; 305 | angular.forEach(scope.defaultValue, function(defaultitem){ 306 | angular.forEach(scope.items, function(item, key) { 307 | if (item[scope.valueProperty]==defaultitem) { 308 | scope.value[key] = scope.getItemValue(item); 309 | item.checked=true; 310 | arrChecked.push(item); 311 | } 312 | }); 313 | }) 314 | scope.itemChecked = arrChecked; 315 | } 316 | } 317 | scope.fetchCheckedDefaultItems(); 318 | 319 | // Watch itemChecked property 320 | scope.$watch(function(){ 321 | return scope.itemChecked; 322 | }, scope.onCheckValueChanged, true); 323 | 324 | // Watch value property 325 | scope.$watch(function(){ 326 | return scope.value; 327 | }, scope.onValueChanged, true); 328 | 329 | // Watch items property 330 | scope.$watch(function(){ 331 | return scope.items; 332 | }, scope.fetchCheckedItems, true); 333 | 334 | // Watch defaultValue property 335 | scope.$watch(function(){ 336 | return scope.defaultValue; 337 | }, scope.fetchCheckedDefaultItems, true); 338 | } 339 | }; 340 | }]); 341 | }()); 342 | -------------------------------------------------------------------------------- /dist/ionic-multiselect.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";angular.module("ionic-multiselect",[]).filter("translateItem",["$injector","$parse",function(e,t){return function(a,n){var l;try{var l=e.get("$filter"),r=t("item."+n.valueProperty),i=r(n);return l("translate")(n.indexTranslate+i)}catch(u){return""}}}]).filter("showTextData",["$injector",function(e){return function(t,a){var n;try{var n=e.get("$filter")}catch(l){}var r=[];if(t.indexOf("^")>-1){r=t.split("^"),r=r.filter(Boolean);for(var i=r.length,u=0;i>u;u++){if(a.isTranslate)var o=n("translate")(a.indexTranslate+r[u].trim());else var o=r[u].trim();r[u]=o}}else a.isTranslate?r.push(n("translate")(a.indexTranslate+t.trim())):r.push(t);return 0==r.length?"":r}}]).provider("multiselect",function(){this.setModalTemplateUrl=function(e){this.modalTemplateUrl=e},this.setTemplateUrl=function(e){this.templateUrl=e},this.$get=function(){return this}}).directive("multiselect",["$ionicModal","multiselect",function(e,t){return{restrict:"E",template:function(e,a){return a.templateUrl||t.templateUrl?"":""},scope:{items:"=",defaultValue:"=",valueChangedCallback:"&valueChanged",getCustomTextCallback:"&getCustomText"},link:function(a,n,l){a.headerText=l.headerText||"",a.text=l.text||"",a.defaultText=l.text||"",a.checkedProperty=l.checkedProperty||"checked",a.textProperty=l.textProperty||"text",a.valueProperty=l.valueProperty||"id",a.isTranslate="true"===l.isTranslate||!1,a.indexTranslate=l.indexTranslate||"",a.modalTemplateUrl=l.modalTemplateUrl||t.modalTemplateUrl,a.modalAnimation=l.modalAnimation,a.noteText=l.noteText||"",a.modalTemplateUrl?e.fromTemplateUrl(a.modalTemplateUrl,{scope:a,animation:a.modalAnimation}).then(function(e){a.modal=e}):a.modal=e.fromTemplate("",{scope:a,animation:a.modalAnimation}),a.$on("$destroy",function(){a.modal.remove()}),a.getItemText=function(e){return a.textProperty?e[a.textProperty]:e},a.getItemValue=function(e){return a.valueProperty?e[a.valueProperty]:e},a.getText=function(e){var t=e?e:[],n="";return t.length?angular.forEach(a.items,function(e,l){for(var r=0;r 2 | 3 |
4 | {{ item }} 5 |
6 | 7 | {{noteText}} 8 |
9 | 10 | -------------------------------------------------------------------------------- /dist/templates/modal-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |