summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoristeven <ignatius.steven@gmail.com>2014-05-17 08:27:00 +0800
committeristeven <ignatius.steven@gmail.com>2014-05-17 08:27:00 +0800
commit2ef3dc3f4413455c3050cd09c7e77d376671f8b4 (patch)
tree6a17817f82be299435cb6574a77ca9adc645030b
parent2865bd8f8625e054f27488c2928cf9e700645a9a (diff)
downloadangular-multi-select-2ef3dc3f4413455c3050cd09c7e77d376671f8b4.zip
angular-multi-select-2ef3dc3f4413455c3050cd09c7e77d376671f8b4.tar.gz
angular-multi-select-2ef3dc3f4413455c3050cd09c7e77d376671f8b4.tar.bz2
allow granular input-model update
-rw-r--r--angular-multi-select.js18
-rw-r--r--angular-multi-select.min.js3
2 files changed, 16 insertions, 5 deletions
diff --git a/angular-multi-select.js b/angular-multi-select.js
index 1197874..e8e0ce8 100644
--- a/angular-multi-select.js
+++ b/angular-multi-select.js
@@ -394,15 +394,27 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', '$
validate();
$scope.refreshSelectedItems();
- // Watch for changes in input model (allow dynamic input)
+ // Watch for changes in input model
+ // Updates multi-select when user select/deselect a single checkbox programatically
+ // https://github.com/isteven/angular-multi-select/issues/8
$scope.$watch( 'inputModel' , function( oldVal, newVal ) {
- if ( $scope.inputModel !== 'undefined' ) {
+ if ( $scope.newVal !== 'undefined' ) {
+ validateProperties( $scope.itemLabel.split( ' ' ), $scope.inputModel );
+ validateProperties( new Array( $scope.tickProperty ), $scope.inputModel );
+ }
+ $scope.refreshSelectedItems();
+ }, true);
+
+ // Watch for changes in input model
+ // This on updates the multi-select when a user load a whole new input-model. We also update the $scope.backUp variable
+ $scope.$watch( 'inputModel' , function( oldVal, newVal ) {
+ if ( $scope.newVal !== 'undefined' ) {
validateProperties( $scope.itemLabel.split( ' ' ), $scope.inputModel );
validateProperties( new Array( $scope.tickProperty ), $scope.inputModel );
}
$scope.backUp = angular.copy( $scope.inputModel );
$scope.refreshSelectedItems();
- });
+ });
// Watch for changes in directive state (disabled or enabled)
$scope.$watch( 'isDisabled' , function( newVal ) {
diff --git a/angular-multi-select.min.js b/angular-multi-select.min.js
index d2b7980..07e76ce 100644
--- a/angular-multi-select.min.js
+++ b/angular-multi-select.min.js
@@ -1,7 +1,6 @@
/*
* Angular JS Multi Select
- * Multi select directive using a dropdown button with checkboxes.
* http://github.com/isteven/angular-multi-select
* Copyright (c) 2014 Ignatius Steven
*/
-angular.module("multi-select",["ng"]).directive("multiSelect",["$sce","$filter",function(e,t){return{restrict:"AE",replace:true,scope:{inputModel:"=",outputModel:"=",buttonLabel:"@",selectionMode:"@",itemLabel:"@",tickProperty:"@",disableProperty:"@",orientation:"@",maxLabels:"@",isDisabled:"=",directiveId:"@",helperElements:"@",onOpen:"&",onClose:"&",onBlur:"&",onFocus:"&"},template:'<span class="multiSelect inlineBlock" >'+'<button type="button" class="multiSelect button multiSelectButton" ng-click="toggleCheckboxes( $event ); refreshSelectedItems();" ng-bind-html="varButtonLabel" ng-focus="onFocus()" ng-blur="onBlur()">'+"</button>"+'<div class="multiSelect checkboxLayer hide">'+'<div class="multiSelect line">'+"<span ng-if=\"!isDisabled && ( displayHelper( 'all' ) || displayHelper( 'none' ) || displayHelper( 'reset' ))\">Select: &nbsp;</span>"+'<button type="button" ng-click="select( \'all\' )" class="multiSelect helperButton" ng-if="!isDisabled && displayHelper( \'all\' )">All</button> '+'<button type="button" ng-click="select( \'none\' )" class="multiSelect helperButton" ng-if="!isDisabled && displayHelper( \'none\' )">None</button> '+'<button type="button" ng-click="select( \'reset\' )" class="multiSelect helperButton" ng-if="!isDisabled && displayHelper( \'reset\' )">Reset</button>'+"</div>"+'<div class="multiSelect line" ng-show="displayHelper( \'filter\' )">'+'Filter: <input class="multiSelect" type="text" ng-model="labelFilter" />'+'&nbsp;<button type="button" class="multiSelect helperButton" ng-click="labelFilter=\'\'">Clear</button>'+"</div>"+'<div ng-repeat="item in (filteredModel = (inputModel | filter:labelFilter ))" ng-class="orientation" class="multiSelect multiSelectItem">'+'<div class="multiSelect acol">'+'<div class="multiSelect" ng-show="item[ tickProperty ]">&#10004;</div>'+"</div>"+'<div class="multiSelect acol">'+'<label class="multiSelect" ng-class="{checkboxSelected:item[ tickProperty ]}">'+'<input class="multiSelect checkbox" type="checkbox" ng-disabled="itemIsDisabled( item )" ng-checked="item[ tickProperty ]" ng-click="syncItems( item, $event )"/>'+'<span class="multiSelect" ng-class="{disabled:itemIsDisabled( item )}" ng-bind-html="writeLabel( item, \'itemLabel\' )"></span>'+"</label>&nbsp;&nbsp;"+"</div>"+"</div>"+"</div>"+"</span>",link:function(t,n,r){t.selectedItems=[];t.backUp=[];t.varButtonLabel="";t.tabIndex=0;t.tabables=null;t.currentButton=null;t.displayHelper=function(e){if(typeof r.helperElements==="undefined"){return true}switch(e.toUpperCase()){case"ALL":if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){return false}else{if(r.helperElements&&t.helperElements.toUpperCase().indexOf("ALL")>=0){return true}}break;case"NONE":if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){return false}else{if(r.helperElements&&t.helperElements.toUpperCase().indexOf("NONE")>=0){return true}}break;case"RESET":if(r.helperElements&&t.helperElements.toUpperCase().indexOf("RESET")>=0){return true}break;case"FILTER":if(r.helperElements&&t.helperElements.toUpperCase().indexOf("FILTER")>=0){return true}break;default:break}};t.syncItems=function(e,n){index=t.inputModel.indexOf(e);t.inputModel[index][t.tickProperty]=!t.inputModel[index][t.tickProperty];if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){t.inputModel[index][t.tickProperty]=true;for(i=0;i<t.inputModel.length;i++){if(i!==index){t.inputModel[i][t.tickProperty]=false}}t.toggleCheckboxes(n)}t.refreshSelectedItems();n.target.focus()};t.refreshSelectedItems=function(){t.varButtonLabel="";t.selectedItems=[];ctr=0;angular.forEach(t.inputModel,function(e,n){if(typeof e!=="undefined"){if(e[t.tickProperty]===true||e[t.tickProperty]==="true"){t.selectedItems.push(e)}}});if(typeof r.outputModel!=="undefined"){t.outputModel=angular.copy(t.selectedItems)}if(t.selectedItems.length===0){t.varButtonLabel="None selected"}else{var n=t.selectedItems.length;if(typeof t.maxLabels!=="undefined"&&t.maxLabels!==""&&t.maxLabels!=="0"){n=t.maxLabels}if(t.selectedItems.length>n){t.more=true}else{t.more=false}angular.forEach(t.selectedItems,function(e,r){if(typeof e!=="undefined"){if(ctr<n){t.varButtonLabel+=(t.varButtonLabel.length>0?", ":"")+t.writeLabel(e,"buttonLabel")}ctr++}});if(t.more===true){t.varButtonLabel+=", ... (Total: "+t.selectedItems.length+")"}}t.varButtonLabel=e.trustAsHtml(t.varButtonLabel+'<span class="multiSelect caret"></span>')};t.itemIsDisabled=function(e){if(e[t.disableProperty]===true){return true}else{if(t.isDisabled===true){return true}else{return false}}};t.writeLabel=function(n,r){var i="";var s=t[r].split(" ");angular.forEach(s,function(e,t){if(typeof e!=="undefined"){angular.forEach(n,function(t,n){if(n==e){i+=" "+t}})}});return e.trustAsHtml(i)};t.toggleCheckboxes=function(e){if(e.target){if(e.target.tagName.toUpperCase()!=="BUTTON"&&e.target.className.indexOf("multiSelectButton")<0){if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){if(e.target.tagName.toUpperCase()==="INPUT"){e=t.findUpTag(e.target,"div","checkboxLayer");e=e.previousSibling}}else{e=t.findUpTag(e.target,"button","multiSelectButton")}}else{e=e.target}}t.labelFilter="";var n=-1;var s=document.querySelectorAll(".checkboxLayer");var o=document.querySelectorAll(".multiSelectButton");for(i=0;i<o.length;i++){if(e===o[i]){n=i;break}}if(n>-1){for(i=0;i<s.length;i++){if(i!=n){s[i].className="multiSelect checkboxLayer hide"}}if(s[n].className=="multiSelect checkboxLayer hide"){t.currentButton=o[n];s[n].className="multiSelect checkboxLayer show";t.onOpen()}else if(s[n].className=="multiSelect checkboxLayer show"){s[n].className="multiSelect checkboxLayer hide";t.onClose()}}};t.findUpTag=function(e,t,n){while(e.parentNode){e=e.parentNode;if(typeof e.tagName!=="undefined"){if(e.tagName.toUpperCase()===t.toUpperCase()&&e.className.indexOf(n)>-1){return e}}}return null};t.select=function(e){var n=[];switch(e.toUpperCase()){case"ALL":angular.forEach(t.inputModel,function(e,n){if(typeof e!=="undefined"&&e[t.disableProperty]!==true){e[t.tickProperty]=true}});break;case"NONE":angular.forEach(t.inputModel,function(e,n){if(typeof e!=="undefined"&&e[t.disableProperty]!==true){e[t.tickProperty]=false}});break;case"RESET":t.inputModel=angular.copy(t.backUp);break;default:}t.refreshSelectedItems()};validate=function(){if(!("inputModel"in r)){console.log("Multi-select error: input-model is not defined! (ID: "+t.directiveId+")")}if(!("buttonLabel"in r)){console.log("Multi-select error: button-label is not defined! (ID: "+t.directiveId+")")}if(!("itemLabel"in r)){console.log("Multi-select error: item-label is not defined! (ID: "+t.directiveId+")")}if(!("tickProperty"in r)){console.log("Multi-select error: tick-property is not defined! (ID: "+t.directiveId+")")}};validateProperties=function(e,n){var r=false;var i="";angular.forEach(e,function(e,t){if(typeof e!=="undefined"){var i=true;angular.forEach(n,function(t,n){if(typeof t!=="undefined"&&i){if(!(e in t)){r=true;i=false;missingLabel=e}}})}});if(r===true){console.log('Multi-select error: property "'+missingLabel+'" is not available in the input model. (Name: '+t.directiveId+")")}};validate();t.refreshSelectedItems();t.$watch("inputModel",function(e,n){if(t.inputModel!=="undefined"){validateProperties(t.itemLabel.split(" "),t.inputModel);validateProperties(new Array(t.tickProperty),t.inputModel)}t.backUp=angular.copy(t.inputModel);t.refreshSelectedItems()});t.$watch("isDisabled",function(e){t.isDisabled=e});angular.element(document).bind("click",function(e){var t=document.querySelectorAll(".checkboxLayer");if(e.target.className.indexOf("multiSelect")===-1){for(i=0;i<t.length;i++){t[i].className="multiSelect checkboxLayer hide"}e.stopPropagation()}});if(!Array.prototype.indexOf){Array.prototype.indexOf=function(e,t){t=t||0;var n=this.length;while(t<n){if(this[t]===e)return t;++t}return-1}}}}}])
+angular.module("multi-select",["ng"]).directive("multiSelect",["$sce","$filter",function(e,t){return{restrict:"AE",replace:true,scope:{inputModel:"=",outputModel:"=",buttonLabel:"@",selectionMode:"@",itemLabel:"@",tickProperty:"@",disableProperty:"@",orientation:"@",maxLabels:"@",isDisabled:"=",directiveId:"@",helperElements:"@",onOpen:"&",onClose:"&",onBlur:"&",onFocus:"&"},template:'<span class="multiSelect inlineBlock" >'+'<button type="button" class="multiSelect button multiSelectButton" ng-click="toggleCheckboxes( $event ); refreshSelectedItems();" ng-bind-html="varButtonLabel" ng-focus="onFocus()" ng-blur="onBlur()">'+"</button>"+'<div class="multiSelect checkboxLayer hide">'+'<div class="multiSelect line">'+"<span ng-if=\"!isDisabled && ( displayHelper( 'all' ) || displayHelper( 'none' ) || displayHelper( 'reset' ))\">Select: &nbsp;</span>"+'<button type="button" ng-click="select( \'all\' )" class="multiSelect helperButton" ng-if="!isDisabled && displayHelper( \'all\' )">All</button> '+'<button type="button" ng-click="select( \'none\' )" class="multiSelect helperButton" ng-if="!isDisabled && displayHelper( \'none\' )">None</button> '+'<button type="button" ng-click="select( \'reset\' )" class="multiSelect helperButton" ng-if="!isDisabled && displayHelper( \'reset\' )">Reset</button>'+"</div>"+'<div class="multiSelect line" ng-show="displayHelper( \'filter\' )">'+'Filter: <input class="multiSelect" type="text" ng-model="labelFilter" />'+'&nbsp;<button type="button" class="multiSelect helperButton" ng-click="labelFilter=\'\'">Clear</button>'+"</div>"+'<div ng-repeat="item in (filteredModel = (inputModel | filter:labelFilter ))" ng-class="orientation" class="multiSelect multiSelectItem">'+'<div class="multiSelect acol">'+'<div class="multiSelect" ng-show="item[ tickProperty ]">&#10004;</div>'+"</div>"+'<div class="multiSelect acol">'+'<label class="multiSelect" ng-class="{checkboxSelected:item[ tickProperty ]}">'+'<input class="multiSelect checkbox" type="checkbox" ng-disabled="itemIsDisabled( item )" ng-checked="item[ tickProperty ]" ng-click="syncItems( item, $event )"/>'+'<span class="multiSelect" ng-class="{disabled:itemIsDisabled( item )}" ng-bind-html="writeLabel( item, \'itemLabel\' )"></span>'+"</label>&nbsp;&nbsp;"+"</div>"+"</div>"+"</div>"+"</span>",link:function(t,n,r){t.selectedItems=[];t.backUp=[];t.varButtonLabel="";t.tabIndex=0;t.tabables=null;t.currentButton=null;t.displayHelper=function(e){if(typeof r.helperElements==="undefined"){return true}switch(e.toUpperCase()){case"ALL":if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){return false}else{if(r.helperElements&&t.helperElements.toUpperCase().indexOf("ALL")>=0){return true}}break;case"NONE":if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){return false}else{if(r.helperElements&&t.helperElements.toUpperCase().indexOf("NONE")>=0){return true}}break;case"RESET":if(r.helperElements&&t.helperElements.toUpperCase().indexOf("RESET")>=0){return true}break;case"FILTER":if(r.helperElements&&t.helperElements.toUpperCase().indexOf("FILTER")>=0){return true}break;default:break}};t.syncItems=function(e,n){index=t.inputModel.indexOf(e);t.inputModel[index][t.tickProperty]=!t.inputModel[index][t.tickProperty];if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){t.inputModel[index][t.tickProperty]=true;for(i=0;i<t.inputModel.length;i++){if(i!==index){t.inputModel[i][t.tickProperty]=false}}t.toggleCheckboxes(n)}t.refreshSelectedItems();n.target.focus()};t.refreshSelectedItems=function(){t.varButtonLabel="";t.selectedItems=[];ctr=0;angular.forEach(t.inputModel,function(e,n){if(typeof e!=="undefined"){if(e[t.tickProperty]===true||e[t.tickProperty]==="true"){t.selectedItems.push(e)}}});if(typeof r.outputModel!=="undefined"){t.outputModel=angular.copy(t.selectedItems)}if(t.selectedItems.length===0){t.varButtonLabel="None selected"}else{var n=t.selectedItems.length;if(typeof t.maxLabels!=="undefined"&&t.maxLabels!==""&&t.maxLabels!=="0"){n=t.maxLabels}if(t.selectedItems.length>n){t.more=true}else{t.more=false}angular.forEach(t.selectedItems,function(e,r){if(typeof e!=="undefined"){if(ctr<n){t.varButtonLabel+=(t.varButtonLabel.length>0?", ":"")+t.writeLabel(e,"buttonLabel")}ctr++}});if(t.more===true){t.varButtonLabel+=", ... (Total: "+t.selectedItems.length+")"}}t.varButtonLabel=e.trustAsHtml(t.varButtonLabel+'<span class="multiSelect caret"></span>')};t.itemIsDisabled=function(e){if(e[t.disableProperty]===true){return true}else{if(t.isDisabled===true){return true}else{return false}}};t.writeLabel=function(n,r){var i="";var s=t[r].split(" ");angular.forEach(s,function(e,t){if(typeof e!=="undefined"){angular.forEach(n,function(t,n){if(n==e){i+=" "+t}})}});return e.trustAsHtml(i)};t.toggleCheckboxes=function(e){if(e.target){if(e.target.tagName.toUpperCase()!=="BUTTON"&&e.target.className.indexOf("multiSelectButton")<0){if(r.selectionMode&&t.selectionMode.toUpperCase()==="SINGLE"){if(e.target.tagName.toUpperCase()==="INPUT"){e=t.findUpTag(e.target,"div","checkboxLayer");e=e.previousSibling}}else{e=t.findUpTag(e.target,"button","multiSelectButton")}}else{e=e.target}}t.labelFilter="";var n=-1;var s=document.querySelectorAll(".checkboxLayer");var o=document.querySelectorAll(".multiSelectButton");for(i=0;i<o.length;i++){if(e===o[i]){n=i;break}}if(n>-1){for(i=0;i<s.length;i++){if(i!=n){s[i].className="multiSelect checkboxLayer hide"}}if(s[n].className=="multiSelect checkboxLayer hide"){t.currentButton=o[n];s[n].className="multiSelect checkboxLayer show";t.onOpen()}else if(s[n].className=="multiSelect checkboxLayer show"){s[n].className="multiSelect checkboxLayer hide";t.onClose()}}};t.findUpTag=function(e,t,n){while(e.parentNode){e=e.parentNode;if(typeof e.tagName!=="undefined"){if(e.tagName.toUpperCase()===t.toUpperCase()&&e.className.indexOf(n)>-1){return e}}}return null};t.select=function(e){var n=[];switch(e.toUpperCase()){case"ALL":angular.forEach(t.inputModel,function(e,n){if(typeof e!=="undefined"&&e[t.disableProperty]!==true){e[t.tickProperty]=true}});break;case"NONE":angular.forEach(t.inputModel,function(e,n){if(typeof e!=="undefined"&&e[t.disableProperty]!==true){e[t.tickProperty]=false}});break;case"RESET":t.inputModel=angular.copy(t.backUp);break;default:}t.refreshSelectedItems()};validate=function(){if(!("inputModel"in r)){console.log("Multi-select error: input-model is not defined! (ID: "+t.directiveId+")")}if(!("buttonLabel"in r)){console.log("Multi-select error: button-label is not defined! (ID: "+t.directiveId+")")}if(!("itemLabel"in r)){console.log("Multi-select error: item-label is not defined! (ID: "+t.directiveId+")")}if(!("tickProperty"in r)){console.log("Multi-select error: tick-property is not defined! (ID: "+t.directiveId+")")}};validateProperties=function(e,n){var r=false;var i="";angular.forEach(e,function(e,t){if(typeof e!=="undefined"){var i=true;angular.forEach(n,function(t,n){if(typeof t!=="undefined"&&i){if(!(e in t)){r=true;i=false;missingLabel=e}}})}});if(r===true){console.log('Multi-select error: property "'+missingLabel+'" is not available in the input model. (Name: '+t.directiveId+")")}};validate();t.refreshSelectedItems();t.$watch("inputModel",function(e,n){if(t.newVal!=="undefined"){validateProperties(t.itemLabel.split(" "),t.inputModel);validateProperties(new Array(t.tickProperty),t.inputModel)}t.refreshSelectedItems()},true);t.$watch("inputModel",function(e,n){if(t.newVal!=="undefined"){validateProperties(t.itemLabel.split(" "),t.inputModel);validateProperties(new Array(t.tickProperty),t.inputModel)}t.backUp=angular.copy(t.inputModel);t.refreshSelectedItems()});t.$watch("isDisabled",function(e){t.isDisabled=e});angular.element(document).bind("click",function(e){var t=document.querySelectorAll(".checkboxLayer");if(e.target.className.indexOf("multiSelect")===-1){for(i=0;i<t.length;i++){t[i].className="multiSelect checkboxLayer hide"}e.stopPropagation()}});if(!Array.prototype.indexOf){Array.prototype.indexOf=function(e,t){t=t||0;var n=this.length;while(t<n){if(this[t]===e)return t;++t}return-1}}}}}])