summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoristeven <isteven@server.fake>2014-03-25 19:09:35 +0800
committeristeven <isteven@server.fake>2014-03-25 19:09:35 +0800
commit0c0a161a27584e96e7475057cba9d218074fbf4a (patch)
treea40797b832275be59b17ec8f3ab88822a25a3294
downloadangular-multi-select-0c0a161a27584e96e7475057cba9d218074fbf4a.zip
angular-multi-select-0c0a161a27584e96e7475057cba9d218074fbf4a.tar.gz
angular-multi-select-0c0a161a27584e96e7475057cba9d218074fbf4a.tar.bz2
First entry
First entry
-rw-r--r--angular-multi-select.css105
-rw-r--r--angular-multi-select.js234
2 files changed, 339 insertions, 0 deletions
diff --git a/angular-multi-select.css b/angular-multi-select.css
new file mode 100644
index 0000000..d54b5f5
--- /dev/null
+++ b/angular-multi-select.css
@@ -0,0 +1,105 @@
+/* app css stylesheet */
+
+.multiSelect {
+}
+
+.multiSelect.inlineBlock {
+ display: inline-block;
+}
+
+.multiSelect .button {
+ display: inline-block;
+ margin-bottom: 0;
+ font-weight: normal;
+ text-align: center;
+ vertical-align: middle;
+ cursor: pointer;
+ background-image: none;
+ border: 1px solid transparent;
+ white-space: nowrap;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.428571429;
+ border-radius: 0px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+.multiSelect .mainColor {
+ background-color: #5CB85C;
+ border-color: #4CAE4C;
+ color: #fff;
+}
+
+.multiSelect .button > div {
+ float: left;
+}
+
+.multiSelect .checkboxLayer {
+ background-color: #fff;
+ position: absolute;
+ z-index: 999;
+ border: 1px solid #cccccc;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ background-clip: padding-box;
+ padding: 15px;
+}
+
+.multiSelect .caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 15px !important;
+ vertical-align: middle;
+ border-top: 4px solid #fff;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+ border-bottom: 0 dotted;
+}
+
+.multiSelect label {
+ margin-right: 0px;
+ margin-bottom: 3px;
+ padding: 5px 8px 5px 8px;
+}
+
+.multiSelect .checkboxSelected {
+ background-color: #428bca;
+ border-color: #357ebd;
+ color: #fff;
+ padding: 4px 7px 4px 7px;
+ border: 1px solid transparent;
+ border-radius: 1px;
+}
+
+.multiSelect .vertical {
+ float: none;
+}
+
+.multiSelect .horizontal {
+ float: left;
+}
+
+.multiSelect input {
+ margin-right: 4px;
+}
+
+.multiSelect .show {
+ display: inline-block;
+}
+
+.multiSelect .hide {
+ display: none;
+}
+
+.multiSelect .line {
+ margin-bottom: 15px;
+}
+
+
diff --git a/angular-multi-select.js b/angular-multi-select.js
new file mode 100644
index 0000000..1ea6960
--- /dev/null
+++ b/angular-multi-select.js
@@ -0,0 +1,234 @@
+/*
+ * Ignatius Steven
+ * Tue, 14 Jan 2014 - 5:18:02 PM
+ *
+ * Angular JS Multi Select
+ * Creates a dropdown-like button with checkboxes. Accepts an array of object & modifies it based on the checkboxes status.
+ *
+ * Usage:
+ *
+ * <div
+ * multi-select
+ * list-items="data"
+ * item-label="firstName lastName"
+ * item-ticker="selected"
+ * orientation="vertical"
+ * max-labels="4"
+ * max-height="500"
+ * is-disabled="false" >
+ * </div>
+ *
+ * or
+ *
+ * <multi-select
+ * ...
+ * ...
+ * </multi-select>
+ * (*** be careful with browser compatibility)
+ *
+ * Attributes:
+ *
+ * list-items (REQUIRED):
+ * $scope variable. Array of objects such as
+ * [
+ * { firstName: "John", lastName: "Robert" , ....., selected: false },
+ * { firstName: "Jane", lastName: "Angel" , ....., selected: true },
+ * { firstName: "Luke", lastName: "Skywalker" , ....., selected: true },
+ * { firstName: "John", lastName: "Wayne" , ....., selected: true }
+ * ]
+ * item-label (String) (REQUIRED)
+ * The object property that you want to display on the button & checkboxes. Separate multiple values by space.
+ * Example: item-label="firstName lastName"
+ * item-ticker (String) (REQUIRED):
+ * Column name with a boolean value that represent the state of a checkbox. For example, in the list-items sample above,
+ * the item-ticker is "selected". So if selected === true, checkbox will be ticked. If selected === false, checkbox will not be ticked.
+ * If not specified, the default will be "selected"
+ * orientation (String - "vertical" | "horizontal")
+ * Orientation of the list of checkboxes.
+ * If not specified, the default will be "vertical".
+ * max-labels (String)
+ * Maximum number of items that will be displayed in the dropdown button. If not specified, will display all selected items.
+ * Example: "2" -> Using the list-items above, then button will display the first two selected: "Jane Angel, Luke Skywalker, ..."
+ * max-height (String)
+ * Maximum height of the list of checkboxes in pixels. Will show scrollbar on overflow.
+ * Example: "100".
+ * is-disabled (String - "true" | "false")
+ * Disable or enable the checkboxes.
+ * If not specified, the default will be "false".
+ *
+ */
+
+angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout', '$compile' , function ( $timeout, $compile ) {
+ return {
+ restrict:
+ 'AE',
+
+ replace:
+ true,
+
+ scope:
+ {
+ listItems : '=',
+ itemLabel : '@',
+ itemTicker : '@',
+ orientation : '@',
+ maxLabels : '@',
+ maxHeight : '@',
+ isDisabled : '=',
+ },
+
+ template:
+ '<span class="multiSelect inlineBlock">' +
+ '<button type="button" class="multiSelect button mainColor multiSelectButton" ng-click="toggleCheckboxes( $event ); refreshSelectedItems();">' +
+ '<div ng-if="selectedItems.length <= 0">None selected</div>' +
+ '<div ng-if="selectedItems.length > 0" ng-repeat="item in selectedItems | limitTo: varMaxLabels">' +
+ '<span ng-if="$index > 0">, </span>{{writeLabel( item )}}' +
+ '</div>' +
+ '<span ng-if="more">, ...</span><span class="caret"></span>' +
+ '</button>' +
+ '<div class="multiSelect checkboxLayer hide" style="{{layerStyle}}">' +
+ '<div class="multiSelect line">' +
+ 'Tick: &nbsp;&nbsp;' +
+ '<a ng-click="select( \'all\' )" class="multiSelect" >All</a> / ' +
+ '<a ng-click="select( \'none\' )" class="multiSelect" >None</a> / ' +
+ '<a ng-click="select( \'reset\' )" class="multiSelect" >Reset</a>' +
+ '</div>' +
+ '<div class="multiSelect line">' +
+ 'Filter: <input class="multiSelect" type="text" ng-model="labelFilter" />' +
+ '<a class="multiSelect" ng-click="labelFilter=\'\'">[Clear]</a>' +
+ '</div>' +
+ '<div ng-repeat="item in listItems | filter:labelFilter" ng-class="orientation" class="multiSelect">' +
+ '<label class="multiSelect" ng-class="{checkboxSelected:item[ itemSelector ]}">' +
+ '<input class="multiSelect" type="checkbox" ng-disabled="isDisabled" ng-checked="item[ itemSelector ]" ng-click="syncItems( item )" />' +
+ '{{writeLabel( item )}}' +
+ '</label>&nbsp;&nbsp;' +
+ '</div>' +
+ '</div>' +
+ '</span>',
+
+ link: function ( $scope, element, attrs ) {
+
+ $scope.selectedItems = [];
+ $scope.backUp = [];
+ $scope.layerStyle = '';
+ $scope.varMaxLabels = 0;
+
+ $scope.syncItems = function( item ) {
+ item[ $scope.itemSelector ] = !item[ $scope.itemSelector ];
+ $scope.refreshSelectedItems();
+ }
+
+ $scope.refreshSelectedItems = function() {
+ $scope.selectedItems = [];
+ angular.forEach( $scope.listItems, function( value, key ) {
+ if ( value[ $scope.itemSelector ] === true || value[ $scope.itemSelector ] === 'true' ) {
+ $scope.selectedItems.push( value );
+ }
+ });
+ if ( $scope.selectedItems.length > $scope.maxLabels ) {
+ $scope.more = true;
+ }
+ else {
+ $scope.more = false;
+ }
+ if ( typeof $scope.maxLabels === 'undefined' ) {
+ $scope.varMaxLabels = $scope.selectedItems.length;
+ }
+ else {
+ $scope.varMaxLabels = $scope.maxLabels;
+ }
+ }
+
+ $scope.toggleCheckboxes = function( e ) {
+
+ $scope.labelFilter = '';
+
+ var multiSelectIndex = -1;
+ var checkboxes = document.querySelectorAll( '.checkboxLayer' );
+ var multiSelectButtons = document.querySelectorAll( '.multiSelectButton' );
+
+ for( i=0; i < multiSelectButtons.length; i++ ) {
+ if ( e.target == multiSelectButtons[ i ] ) {
+ multiSelectIndex = i;
+ break;
+ }
+ }
+
+ for( i=0; i < checkboxes.length; i++ ) {
+ if ( i != multiSelectIndex ) {
+ checkboxes[i].className = 'multiSelect checkboxLayer hide';
+ }
+ }
+
+ if ( checkboxes[ multiSelectIndex ].className == 'multiSelect checkboxLayer hide' ) {
+ checkboxes[ multiSelectIndex ].className = 'multiSelect checkboxLayer show';
+ }
+ else if ( checkboxes[ multiSelectIndex ].className == 'multiSelect checkboxLayer show' ) {
+ checkboxes[ multiSelectIndex ].className = 'multiSelect checkboxLayer hide';
+ }
+ }
+
+ $scope.select = function( type ) {
+ switch( type.toUpperCase() ) {
+ case 'ALL':
+ angular.forEach( $scope.listItems, function( value, key ) {
+ value[ $scope.itemSelector ] = true;
+ });
+ break;
+ case 'NONE':
+ angular.forEach( $scope.listItems, function( value, key ) {
+ value[ $scope.itemSelector ] = false;
+ });
+ break;
+ case 'RESET':
+ $scope.listItems = angular.copy( $scope.backUp );
+ break;
+ default:
+ }
+ $scope.refreshSelectedItems();
+ }
+
+ $scope.writeLabel= function( item ) {
+ var label = '';
+ angular.forEach( item, function( value1, key1 ) {
+ var temp = $scope.itemLabel.split( ' ' );
+ angular.forEach( temp, function( value2, key2 ) {
+ if ( key1 == value2 ) {
+ label += ' ' + value1;
+ }
+ });
+ });
+ return label;
+ }
+
+ angular.element( document ).bind( 'click' , function( e ) {
+ 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';
+ }
+ $scope.$apply();
+ e.stopPropagation();
+ }
+ });
+
+ // Start
+ $scope.itemSelector = ( typeof $scope.itemTicker === 'string' ? $scope.itemTicker : 'selected' );
+ $scope.refreshSelectedItems();
+
+ $scope.$watch( 'listItems' , function( newVal ) {
+ $scope.refreshSelectedItems();
+ $scope.backUp = angular.copy( $scope.listItems );
+ });
+
+ $scope.$watch( 'isDisabled' , function( newVal ) {
+ $scope.isDisabled = newVal;
+ });
+
+ if ( typeof $scope.maxHeight !== 'undefined' ) {
+ $scope.layerStyle = 'max-height:' + $scope.maxHeight + 'px; overflow: auto; min-width: auto';
+ }
+ }
+ }
+}]);
+