Skip to content

Commit

Permalink
v1.1.0. Callbacks and helper elements config
Browse files Browse the repository at this point in the history
  • Loading branch information
isteven committed May 11, 2014
1 parent 32820f9 commit 1ec7806
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 47 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Angular Multi Select
====================
Angular MultiSelect
==
An AngularJS directive which creates a dropdown button with multiple or single selections.
Allows you to customize your labels and use some HTML tags in the data. Fully configurable through element attributes and CSS.
Doesn't require jQuery and works well with other Javascript libraries.
Expand Down
23 changes: 17 additions & 6 deletions angular-multi-select.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
border-top: 4px solid #333;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
border-bottom: 0 dotted;
border-bottom: 0 dotted;
}

.multiSelect.multiSelectItem {
Expand Down Expand Up @@ -110,11 +110,6 @@ label.multiSelect span {
user-select: none;
}

label.multiSelect span:hover{
cursor: pointer;
color: #333;
}

/* hide the checkbox away */
.multiSelect .checkbox {
position: absolute;
Expand All @@ -138,6 +133,22 @@ label.multiSelect span:hover{
margin-left: 1px;
}

/* On mouse over and focus */
label.multiSelect input:focus ~ span::after,
label.multiSelect span:focus::after,
label.multiSelect span:hover::after {
/* Enable this if you want some arrow pointer */
/* content: ' \00AB'; */
}

label.multiSelect input:focus ~ span,
label.multiSelect span:hover {
color: #333;
cursor: pointer;
/* Enable this if you want some arrow pointer */
/* content: ' \00AB'; */
}

/* for checkboxes currently selected */
.multiSelect .checkboxSelected {
color: #000;
Expand Down
120 changes: 82 additions & 38 deletions angular-multi-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* --------------------------------------------------------------------------------
*/

angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', function ( $sce ) {
angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', '$filter', function ( $sce, $filter ) {
return {
restrict:
'AE',
Expand All @@ -52,47 +52,93 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
maxLabels : '@',
isDisabled : '=',
directiveId : '@',
// JH DotComIt Added 5/8/2014
onPopupopen: '&onPopupopen',
onPopupclose: '&onPopupclose'
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">' +
'<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">Select: &nbsp;</span>' +
'<button type="button" ng-click="select( \'all\' )" class="multiSelect helperButton" ng-if="!isDisabled && selectionMode.toUpperCase() != \'SINGLE\'">All</button> ' +
'<button type="button" ng-click="select( \'none\' )" class="multiSelect helperButton" ng-if="!isDisabled && selectionMode.toUpperCase() != \'SINGLE\'">None</button> ' +
'<button type="button" ng-click="select( \'reset\' )" class="multiSelect helperButton" ng-if="!isDisabled">Reset</button>' +
'<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">' +
'<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 inputModel | filter:labelFilter" ng-class="orientation" class="multiSelect multiSelectItem">' +
'<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>' +
'<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 ( $scope, element, attrs ) {
link: function ( $scope, element, attrs ) {

$scope.selectedItems = [];
$scope.backUp = [];
$scope.varButtonLabel = '';
$scope.varButtonLabel = '';
$scope.tabIndex = 0;
$scope.tabables = null;
$scope.currentButton = null;

// Show or hide a helper element
$scope.displayHelper = function( elementString ) {
if ( typeof attrs.helperElements === 'undefined' ) {
return true;
}
switch( elementString.toUpperCase() ) {
case 'ALL':
if ( attrs.selectionMode && $scope.selectionMode.toUpperCase() === 'SINGLE' ) {
return false;
}
else {
if ( attrs.helperElements && $scope.helperElements.toUpperCase().indexOf( 'ALL' ) >= 0 ) {
return true;
}
}
break;
case 'NONE':
if ( attrs.selectionMode && $scope.selectionMode.toUpperCase() === 'SINGLE' ) {
return false;
}
else {
if ( attrs.helperElements && $scope.helperElements.toUpperCase().indexOf( 'NONE' ) >= 0 ) {
return true;
}
}
break;
case 'RESET':
if ( attrs.helperElements && $scope.helperElements.toUpperCase().indexOf( 'RESET' ) >= 0 ) {
return true;
}
break;
case 'FILTER':
if ( attrs.helperElements && $scope.helperElements.toUpperCase().indexOf( 'FILTER' ) >= 0 ) {
return true;
}
break;
default:
break;
}
}

// Checkbox is ticked
// Call this function when a checkbox is ticked...
$scope.syncItems = function( item, e ) {
index = $scope.inputModel.indexOf( item );
$scope.inputModel[ index ][ $scope.tickProperty ] = !$scope.inputModel[ index ][ $scope.tickProperty ];
Expand All @@ -107,8 +153,9 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
}
$scope.toggleCheckboxes( e );
}

$scope.refreshSelectedItems();

$scope.refreshSelectedItems();
e.target.focus();
}

// Refresh the button to display the selected items and push into output model if specified
Expand Down Expand Up @@ -199,7 +246,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
return $sce.trustAsHtml( label );
}

// UI operations to show/hide checkboxes
// UI operations to show/hide checkboxes based on click event..
$scope.toggleCheckboxes = function( e ) {

if ( e.target ) {
Expand Down Expand Up @@ -238,20 +285,19 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
for( i=0; i < checkboxes.length; i++ ) {
if ( i != multiSelectIndex ) {
checkboxes[i].className = 'multiSelect checkboxLayer hide';
// JH DotComIt 5/8/2014 Added method handler for closing the popup
$scope.onPopupclose();
}
}

if ( checkboxes[ multiSelectIndex ].className == 'multiSelect checkboxLayer hide' ) {
$scope.currentButton = multiSelectButtons[ multiSelectIndex ];
checkboxes[ multiSelectIndex ].className = 'multiSelect checkboxLayer show';
// JH DotComIt 5/8/2014 Added method handler for opening the popup
$scope.onPopupopen();
// https://github.com/isteven/angular-multi-select/pull/5 - On open callback
$scope.onOpen();
}
else if ( checkboxes[ multiSelectIndex ].className == 'multiSelect checkboxLayer show' ) {
checkboxes[ multiSelectIndex ].className = 'multiSelect checkboxLayer hide';
// JH DotComIt 5/8/2014 Added method handler for closing the popup
$scope.onPopupclose();
// https://github.com/isteven/angular-multi-select/pull/5 - On close callback
$scope.onClose();
}
}
}
Expand Down Expand Up @@ -289,8 +335,8 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
}
});
break;
case 'RESET':
$scope.inputModel = angular.copy( $scope.backUp );
case 'RESET':
$scope.inputModel = angular.copy( $scope.backUp );
break;
default:
}
Expand All @@ -299,6 +345,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu


// Generic validation for required attributes
// Might give false positives so just ignore if everything's alright.
validate = function() {
if ( !( 'inputModel' in attrs )) {
console.log( 'Multi-select error: input-model is not defined! (ID: ' + $scope.directiveId + ')' );
Expand Down Expand Up @@ -337,17 +384,16 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
});
if ( notThere === true ) {
console.log( 'Multi-select error: property "' + missingLabel + '" is not available in the input model. (Name: ' + $scope.directiveId + ')' );
}

}
}
}

///////////////////////
// Logic starts here
///////////////////////

validate();
$scope.refreshSelectedItems();

$scope.refreshSelectedItems();
// Watch for changes in input model (allow dynamic input)
$scope.$watch( 'inputModel' , function( oldVal, newVal ) {
if ( $scope.inputModel !== 'undefined' ) {
Expand All @@ -368,14 +414,12 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', fu
var checkboxes = document.querySelectorAll( '.checkboxLayer' );
if ( e.target.className.indexOf( 'multiSelect' ) === -1 ) {
for( i=0; i < checkboxes.length; i++ ) {
checkboxes[i].className = 'multiSelect checkboxLayer hide';
// JH DotComIt 5/8/2014 Added method handler for closing the popup
$scope.onPopupclose();
checkboxes[i].className = 'multiSelect checkboxLayer hide';
}
e.stopPropagation();
}
});

});
// For IE8, perhaps. Not sure if this is really executed.
if ( !Array.prototype.indexOf ) {
Array.prototype.indexOf = function(what, i) {
Expand Down
Loading

0 comments on commit 1ec7806

Please sign in to comment.