summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--angular-multi-select.css82
-rw-r--r--angular-multi-select.js53
-rw-r--r--multiselect.htm178
4 files changed, 205 insertions, 121 deletions
diff --git a/README.md b/README.md
index ea61067..81af2de 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-Angular Multi Select
+Angular Multi Select ** Updating in progress. Do not download **
====================
-Angular Multi Select is an AngularJS directive which creates a dropdown button with multiple checkboxes.
+Angular Multi Select is an AngularJS directive which creates a dropdown button with multiple selections.
<br />![Screenshot](https://raw.githubusercontent.com/isteven/angular-multi-select/master/screenshot.jpg)
@@ -8,6 +8,7 @@ Demo: http://jsfiddle.net/Rg2pY/ or download all the files into a same folder an
Features
--
+ - Use CSS & HTML tags
- Reset selections to original state
- Directly updates the input model
- Load new input model on the fly
@@ -24,6 +25,7 @@ Usage
<div
multi-select
input-model="input_list"
+ button-label="firstName"
item-label="firstName lastName"
tick-property="selected"
output-model="output_list"
@@ -58,8 +60,13 @@ $scope variable. Array of objects.
];
- **IMPORTANT**: This directive updates the $scope variable (input-model) directly, therefore you cannot use the same $scope variable for multiple multi-select directives. You need to copy the input variable to a new one and use it on the second multi-select, and so on.
+##### button-label (REQUIRED)
+input-model property that you want to display on the button. Separate multiple values by space.
+<br />Example:
+item-label="firstName"
+
##### item-label (REQUIRED)
-input-model property that you want to display on the button & checkboxes. Separate multiple values by space.
+input-model property that you want to display on the checkboxes. Separate multiple values by space.
<br />Example:
item-label="firstName lastName"
diff --git a/angular-multi-select.css b/angular-multi-select.css
index ad4372a..6ee29fc 100644
--- a/angular-multi-select.css
+++ b/angular-multi-select.css
@@ -1,7 +1,3 @@
-body {
- font-family: "Arial";
- font-size: 14px;
-}
.multiSelect {
}
@@ -13,39 +9,32 @@ body {
display: block;
position: relative;
margin:0 auto;
- font-weight: normal;
text-align: center;
- vertical-align: middle;
cursor: pointer;
background-image: none;
- border: 1px solid transparent;
+ border: 1px solid #999;
padding: 6px 12px;
font-size: 14px;
- line-height: 1.428571429;
- border-radius: 0px;
+ line-height: 1.4;
+ border-radius: 2px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
- background-color: #5CB85C;
- border-color: #4CAE4C;
- color: #fff;
+ color: #666;
}
.multiSelect .helperButton {
display: inline-block;
- margin-bottom: 0;
- font-weight: normal;
text-align: center;
- vertical-align: middle;
+ vertical-align: top;
cursor: pointer;
- background-image: none;
border: 1px solid #ccc;
- padding: 2px 2px;
+ padding: 2px 7px;
font-size: 14px;
line-height: 1;
- border-radius: 0px;
+ border-radius: 2px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
@@ -83,23 +72,10 @@ body {
border-bottom: 0 dotted;
}
-.multiSelect label {
- margin-right: 0px;
- margin-bottom: 3px;
- padding: 5px 8px 5px 8px;
-}
-
.multiSelect.multiSelectItem {
- padding: 5px 0 5px 0;
-}
-
-.multiSelect .checkboxSelected {
- background-color: #428bca;
- border-color: #357ebd;
- color: #fff;
- padding: 4px 7px 4px 7px;
- border: 1px solid transparent;
- border-radius: 1px;
+ display: block;
+ min-height: 30px;
+ color: #666;
}
.multiSelect .vertical {
@@ -110,8 +86,35 @@ body {
float: left;
}
-.multiSelect input {
- margin-right: 4px;
+.multiSelect .col {
+ display: table-cell;
+ min-width: 14px;
+ line-height: 1.4;
+}
+
+.multiSelect img {
+ vertical-align: middle;
+ margin-bottom:4px;
+}
+
+label.multiSelect span {
+ margin-right: 5px;
+}
+
+label.multiSelect span:hover{
+ cursor: pointer;
+ color: #000;
+}
+
+.multiSelect .checkbox {
+ position: absolute;
+ left: -9999px;
+ cursor: pointer;
+}
+
+.multiSelect .checkboxSelected {
+ color: #333;
+ font-weight: bold;
}
.multiSelect .show {
@@ -127,6 +130,11 @@ body {
}
.multiSelect .helperButton + .helperButton {
- margin-left: 5px;
+ margin-left: 1px;
+}
+
+.multiSelect.disabled {
+ color: #999;
+ cursor: not-allowed;
}
diff --git a/angular-multi-select.js b/angular-multi-select.js
index e46360b..897a596 100644
--- a/angular-multi-select.js
+++ b/angular-multi-select.js
@@ -31,7 +31,7 @@
* --------------------------------------------------------------------------------
*/
-angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout', '$compile' , function ( $timeout, $compile ) {
+angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$sce', function ( $sce ) {
return {
restrict:
'AE',
@@ -43,6 +43,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
{
inputModel : '=',
outputModel : '=',
+ buttonLabel : '@',
itemLabel : '@',
tickProperty : '@',
orientation : '@',
@@ -53,10 +54,8 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
template:
'<span class="multiSelect inlineBlock">' +
- '<div class="multiSelect button multiSelectButton" ng-click="toggleCheckboxes( $event ); refreshSelectedItems();">' +
- '{{buttonLabel}}' +
- ' &nbsp;&#9662;' +
- '</div>' +
+ '<button type="button" class="multiSelect button multiSelectButton" ng-click="toggleCheckboxes( $event ); refreshSelectedItems();" ng-bind-html="varButtonLabel">' +
+ '</button>' +
'<div class="multiSelect checkboxLayer hide" style="{{layerStyle}}">' +
'<div class="multiSelect line">' +
'<span ng-if="!isDisabled">Select: &nbsp;&nbsp;</span>' +
@@ -66,13 +65,18 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
'</div>' +
'<div class="multiSelect line">' +
'Filter: <input class="multiSelect" type="text" ng-model="labelFilter" />' +
- '<button type="button" class="multiSelect helperButton" ng-click="labelFilter=\'\'">Clear</button>' +
+ '&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">' +
- '<label class="multiSelect" ng-class="{checkboxSelected:item[ tickProperty ]}">' +
- '<input class="multiSelect" type="checkbox" ng-disabled="isDisabled" ng-checked="item[ tickProperty ]" ng-click="syncItems( item )" />' +
- '{{writeLabel( item )}}' +
- '</label>&nbsp;&nbsp;' +
+ '<div class="multiSelect col">' +
+ '<span class="multiSelect" ng-if="item[ tickProperty ]">&#10004;</span>' +
+ '</div>' +
+ '<div class="multiSelect col">' +
+ '<label class="multiSelect" ng-class="{checkboxSelected:item[ tickProperty ]}">' +
+ '<input class="multiSelect checkbox" type="checkbox" ng-disabled="isDisabled" ng-checked="item[ tickProperty ]" ng-click="syncItems( item )" />' +
+ '<span class="multiSelect" ng-class="{disabled:isDisabled}" ng-bind-html="writeLabel( item, \'itemLabel\' )"></span>' +
+ '</label>&nbsp;&nbsp;' +
+ '</div>' +
'</div>' +
'</div>' +
'</span>',
@@ -82,7 +86,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
$scope.selectedItems = [];
$scope.backUp = [];
$scope.layerStyle = '';
- $scope.buttonLabel = '';
+ $scope.varButtonLabel = '';
// Checkbox is ticked
$scope.syncItems = function( item ) {
@@ -94,7 +98,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
// Refresh the button to display the selected items and push into output model if specified
$scope.refreshSelectedItems = function() {
- $scope.buttonLabel = '';
+ $scope.varButtonLabel = '';
$scope.selectedItems = [];
ctr = 0;
@@ -113,7 +117,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
// Write label...
if ( $scope.selectedItems.length === 0 ) {
- $scope.buttonLabel = 'None selected';
+ $scope.varButtonLabel = 'None selected';
}
else {
var tempMaxLabels = $scope.selectedItems.length;
@@ -132,22 +136,23 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
angular.forEach( $scope.selectedItems, function( value, key ) {
if ( typeof value !== 'undefined' ) {
if ( ctr < tempMaxLabels ) {
- $scope.buttonLabel += ( $scope.buttonLabel.length > 0 ? ', ' : '') + $scope.writeLabel( value );
+ $scope.varButtonLabel += ( $scope.varButtonLabel.length > 0 ? ', ' : '') + $scope.writeLabel( value, 'buttonLabel' );
}
ctr++;
}
});
if ( $scope.more === true ) {
- $scope.buttonLabel += ', ... (Total: ' + $scope.selectedItems.length + ')';
+ $scope.varButtonLabel += ', ... (Total: ' + $scope.selectedItems.length + ')';
}
}
+ $scope.varButtonLabel = $sce.trustAsHtml( $scope.varButtonLabel + '&nbsp;&nbsp;&#9662;' );
}
// A simple function to parse the item label settings
- $scope.writeLabel = function( item ) {
+ $scope.writeLabel = function( item, type ) {
var label = '';
- var temp = $scope.itemLabel.split( ' ' );
+ var temp = $scope[ type ].split( ' ' );
angular.forEach( temp, function( value2, key2 ) {
if ( typeof value2 !== 'undefined' ) {
angular.forEach( item, function( value1, key1 ) {
@@ -157,7 +162,7 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
});
}
});
- return label;
+ return $sce.trustAsHtml( label );
}
// UI operations to show/hide checkboxes
@@ -223,15 +228,19 @@ angular.module( 'multi-select', ['ng'] ).directive( 'multiSelect' , [ '$timeout'
// Generic validation for required attributes
validate = function() {
if ( !( 'inputModel' in attrs )) {
- console.log( 'Multi-select error: input model is not defined! (ID: ' + $scope.directiveId + ')' );
+ console.log( 'Multi-select error: input-model is not defined! (ID: ' + $scope.directiveId + ')' );
}
- if ( !( 'itemLabel' in attrs )) {
- console.log( 'Multi-select error: item label is not defined! (ID: ' + $scope.directiveId + ')' );
+ if ( !( 'buttonLabel' in attrs )) {
+ console.log( 'Multi-select error: button-label is not defined! (ID: ' + $scope.directiveId + ')' );
}
+ if ( !( 'itemLabel' in attrs )) {
+ console.log( 'Multi-select error: item-label is not defined! (ID: ' + $scope.directiveId + ')' );
+ }
+
if ( !( 'tickProperty' in attrs )) {
- console.log( 'Multi-select error: tick property is not defined! (ID: ' + $scope.directiveId + ')' );
+ console.log( 'Multi-select error: tick-property is not defined! (ID: ' + $scope.directiveId + ')' );
}
}
diff --git a/multiselect.htm b/multiselect.htm
index 4234e40..87b904d 100644
--- a/multiselect.htm
+++ b/multiselect.htm
@@ -9,61 +9,94 @@
<!-- css -->
<link rel="stylesheet" href="angular-multi-select.css">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
+ <style>
+ body {
+ font-family: 'Arial';
+ font-size: 14px;
+ background-color: #999;
+ padding: 0;
+ margin: 20px;
+ }
+ #container {
+ margin: 0px auto;
+ width: 50%;
+ background-color: #ccc;
+ padding: 20px;
+ }
+ </style>
</head>
<body ng-controller="main">
-
- * Open your browser console to see the $scope variables getting updated
- <br />
- <br />
-
- Minimal:
- <br />
- <div
- multi-select
- input-model="minData"
- item-label="firstName"
- tick-property="selected"
- >
+ <div id="container">
+ * Open your browser console to see the $scope variables getting updated
+
+ <br />
+ <h3 style="width:100%;border-bottom:1px solid #888">Minimal</h3>
+ <div
+ multi-select
+ input-model="minData"
+ button-label="firstName"
+ item-label="firstName"
+ tick-property="selected"
+ >
+ </div>
+ <br />
+ <br />
+ <br />
+ <br />
+
+ <h3 style="width:100%;border-bottom:1px solid #888">Full</h3>
+ <div
+ multi-select
+ input-model="fullData"
+ output-model="resultData"
+ button-label="firstName lastName"
+ item-label="firstName lastName"
+ tick-property="checked"
+ orientation="horizontal"
+ max-labels="3"
+ directive-id="multiSelectFull"
+ >
+ </div>
+ <br />
+ <br />
+ <br />
+ <br />
+
+ <h3 style="width:100%;border-bottom:1px solid #888">Use element instead of attribute, dynamic input and state</h3>
+ <multi-select
+ input-model="dynamicData"
+ button-label="car"
+ item-label="car"
+ tick-property="ticked"
+ is-disabled="dinDisabled"
+ >
+ </multi-select>
+
+ <br /><br />
+ <button type="button" ng-click="switchSource( 'data1' )" >Load data 1</button>
+ <button type="button" ng-click="switchSource( 'data2' )" >Load data 2</button>
+ <button type="button" ng-click="switchSource( 'data3' )" >Load data 3</button>
+
+ <br /><br />
+ <button type="button" ng-click="dinDisabled = !dinDisabled" >Enable / Disable</button>
+ Is disabled: {{dinDisabled}}
+ <br />
+ <br />
+ <br />
+ <br />
+
+ <h3 style="width:100%;border-bottom:1px solid #888">Use HTML tags</h3>
+ You can use whatever HTML tags accepted by AngularJS's $sce.trustAsHtml() method.
+ <br /><br />
+ <multi-select
+ input-model="webBrowsers"
+ button-label="icon"
+ item-label="icon name"
+ tick-property="ticked"
+ >
+ </multi-select>
</div>
-
- <br /><br />
-
- Full:
- <br />
- <div
- multi-select
- input-model="fullData"
- output-model="resultData"
- item-label="firstName lastName"
- tick-property="checked"
- orientation="horizontal"
- max-labels="3"
- directive-id="multiSelectFull"
- >
- </div>
-
- <br /><br />
-
- Use element instead of attribute, load input model on the fly, and toggle checkbox state
- <br />
- <multi-select
- input-model="dynamicData"
- item-label="car"
- tick-property="ticked"
- is-disabled="dinDisabled"
- >
- </multi-select>
-
- <br /><br />
- <button type="button" ng-click="switchSource( 'data1' )" >Load data 1</button>
- <button type="button" ng-click="switchSource( 'data2' )" >Load data 2</button>
- <button type="button" ng-click="switchSource( 'data3' )" >Load data 3</button>
-
- <br /><br />
- <button type="button" ng-click="dinDisabled = !dinDisabled" >Enable / Disable</button>
- Is disabled: {{dinDisabled}}
-
</body>
<script>
@@ -149,19 +182,19 @@ myApp.controller( 'main' , [ '$scope' , function ($scope) {
$scope.dynamicData = $scope[ data ];
}
- // Japan cars
+ // Japanese cars
$scope.data1 = [
- { car: 'Toyota' , ticked: true },
- { car: 'Mazda' , ticked: false },
- { car: 'Nissan' , ticked: true },
- { car: 'Honda' , ticked: false }
+ { car: 'Toyota', ticked: true },
+ { car: 'Mazda', ticked: false },
+ { car: 'Nissan', ticked: true },
+ { car: 'Honda', ticked: false }
];
// German cars
$scope.data2 = [
- { car: 'Audi' , ticked: false },
- { car: 'BMW' , ticked: false },
- { car: 'Mercedes' , ticked: true },
+ { car: 'Audi', ticked: false },
+ { car: 'BMW', ticked: false },
+ { car: 'Mercedes', ticked: true },
];
// Italian cars
@@ -183,6 +216,33 @@ myApp.controller( 'main' , [ '$scope' , function ($scope) {
console.log( '--------' );
}
}, true );
+
+ /////////////
+ // HTML tag
+ /////////////
+
+ // Web browsers
+ $scope.webBrowsers = [
+ { icon: '<img class="multiSelect" src="https://cdn1.iconfinder.com/data/icons/fatcow/32/opera.png" />', name: 'Opera', ticked: true },
+ { icon: '<img class="multiSelect" src="https://cdn1.iconfinder.com/data/icons/fatcow/32/internet_explorer.png" />', name: 'Internet Explorer', ticked: false },
+ { icon: '<img class="multiSelect" src="https://cdn1.iconfinder.com/data/icons/humano2/32x32/apps/firefox-icon.png" />', name: 'Firefox', ticked: true },
+ { icon: '<img class="multiSelect" src="https://cdn1.iconfinder.com/data/icons/fatcow/32x32/safari_browser.png" />', name: 'Safari', ticked: false },
+ { icon: '<img class="multiSelect" src="https://cdn1.iconfinder.com/data/icons/google_jfk_icons_by_carlosjj/32/chrome.png" />', name: 'Chrome', ticked: true }
+ ];
+
+ // Open your console and watch dynamicData changes
+ $scope.$watch( "webBrowsers" , function( newVal, oldVal ) {
+ if ( !angular.equals( oldVal, newVal ) ) {
+ angular.forEach( newVal , function( value, key ) {
+ if ( value.ticked === true ) {
+ console.log( 'dynamicData .ticked === true: ' + value.car );
+ }
+ });
+ console.log( '--------' );
+ }
+ }, true );
+
+
}]);
</script>