Document multi-select-list directive

This commit is contained in:
Joe Fiorini
2015-03-18 11:22:05 -04:00
parent 9fd0184131
commit 4122be0211
11 changed files with 331 additions and 12 deletions

View File

@@ -1 +1 @@
import 'tower/debug'; import 'tower/shared/multi-select-list/main.js';

View File

@@ -8,7 +8,7 @@
*/ */
/** /**
* @ngdoc function * @ngdoc function
* @name forms.function:Organizations * @name forms.function:CustomInventory
* @description This form is for adding/editing an organization * @description This form is for adding/editing an organization
*/ */

View File

@@ -3,7 +3,7 @@
*/ */
/** /**
* @ngdoc function * @ngdoc function
* @name helpers.function:Schedules * @name helpers.function:ConfigureTower
* @description * @description
* Schedules Helper * Schedules Helper
* *

View File

@@ -3,7 +3,7 @@
*/ */
/** /**
* @ngdoc function * @ngdoc function
* @name helpers.function:Schedules * @name helpers.function:CustomInventory
* @description * @description
* Schedules Helper * Schedules Helper
* *

View File

@@ -3,7 +3,7 @@
*/ */
/** /**
* @ngdoc function * @ngdoc function
* @name helpers.function:Schedules * @name helpers.function:Survey
* @description * @description
* Schedules Helper * Schedules Helper
* *

View File

@@ -1,3 +1,12 @@
/**
* @ngdoc object
* @name multiSelectList.controller:multiSelectList
*
* @description
*
* `multiSelectList` controller provides the API for the {@link multiSelectList.directive:multiSelectList `multiSelectList`} directive. The controller contains methods for selecting/deselecting items, controlling the extended selection, registering items to be selectable and emitting an event on the directive's `$scope`.
*
*/
export default ['$scope', export default ['$scope',
function ($scope) { function ($scope) {
$scope.items = []; $scope.items = [];
@@ -7,10 +16,11 @@ export default ['$scope',
deselectedItems: [] deselectedItems: []
}; };
// Makes $scope.selection.length an alias for $scope.selectedItems.length
Object.defineProperty($scope.selection, Object.defineProperty($scope.selection,
'length', 'length',
{ get: function() { { get: function() {
return this.items.length; return this.selectedItems.length;
} }
}); });
@@ -26,15 +36,41 @@ export default ['$scope',
_items.pluck('value').difference($scope.selection.selectedItems) _items.pluck('value').difference($scope.selection.selectedItems)
.value(); .value();
/**
*
* @ngdoc event
* @name multiSelectList.selectionChanged
* @eventOf multiSelectList.directive:multiSelectList
*
*/
$scope.$emit('multiSelectList.selectionChanged', $scope.selection); $scope.$emit('multiSelectList.selectionChanged', $scope.selection);
} }
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#registerItem
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Prepares an object to be tracked in the select list. Returns the
* decorated item created by
* {@link multiSelectList.controller:multiSelectList#decorateItem `decorateItem`}
*/
this.registerItem = function(item) { this.registerItem = function(item) {
var decoratedItem = this.decorateItem(item); var decoratedItem = this.decorateItem(item);
$scope.items = $scope.items.concat(decoratedItem); $scope.items = $scope.items.concat(decoratedItem);
return decoratedItem; return decoratedItem;
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#deregisterItem
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Removes an item from the list; called if the item is removed from the display
* so that it is no longer tracked as a selectable item.
*/
this.deregisterItem = function(leavingItem) { this.deregisterItem = function(leavingItem) {
$scope.items = $scope.items.filter(function(item) { $scope.items = $scope.items.filter(function(item) {
return leavingItem !== item; return leavingItem !== item;
@@ -42,6 +78,18 @@ export default ['$scope',
rebuildSelections(); rebuildSelections();
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#decorateItem
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
*
* This decorates an item with an object that has an `isSelected` property.
* This value is used to determine the lists of selected and non-selected
* items to emit with the `multiSelectList.selectionChanged`
* event.
*/
this.decorateItem = function(item) { this.decorateItem = function(item) {
return { return {
isSelected: false, isSelected: false,
@@ -49,12 +97,31 @@ export default ['$scope',
}; };
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#selectAll
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Marks all items in the list as selected.
* Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
*/
this.selectAll = function() { this.selectAll = function() {
$scope.items.forEach(function(item) { $scope.items.forEach(function(item) {
item.isSelected = true; item.isSelected = true;
}); });
rebuildSelections();
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#deselectAll
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Marks all items in the list as not selected.
* Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
*/
this.deselectAll = function() { this.deselectAll = function() {
$scope.items.forEach(function(item) { $scope.items.forEach(function(item) {
item.isSelected = false; item.isSelected = false;
@@ -64,19 +131,59 @@ export default ['$scope',
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#deselectAllExtended
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Disables extended selection.
* Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
*/
this.deselectAllExtended = function(extendedLength) { this.deselectAllExtended = function(extendedLength) {
$scope.selection.isExtended = false; $scope.selection.isExtended = false;
rebuildSelections();
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#selectAllExtended
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Enables extended selection.
* Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
*/
this.selectAllExtended = function(extendedLength) { this.selectAllExtended = function(extendedLength) {
$scope.selection.isExtended = true; $scope.selection.isExtended = true;
rebuildSelections();
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#selectItem
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Marks an item as selected.
* Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
*
*/
this.selectItem = function(item) { this.selectItem = function(item) {
item.isSelected = true; item.isSelected = true;
rebuildSelections(); rebuildSelections();
}; };
/**
* @ngdoc
* @name multiSelectList.controller:multiSelectList#deregisterItem
* @methodOf multiSelectList.controller:multiSelectList
*
* @description
* Marks an item as not selected.
* Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
*
*/
this.deselectItem = function(item) { this.deselectItem = function(item) {
item.isSelected = false; item.isSelected = false;
rebuildSelections(); rebuildSelections();

View File

@@ -1,8 +1,75 @@
/**
* @ngdoc overview
* @name multiSelectList
* @scope
* @description Does some stuff
*
* @ngdoc directive
* @name multiSelectList.directive:multiSelectList
* @description
* The `multiSelectList` directive works in conjunction with the
* `selectListItem` and (optionally) the `selectAll` directives to
* render checkboxes with list items and tracking the selected state
* of each item. The `selectListItem` directive renders a checkbox,
* and the `multiSelectList` directive tracks the selected state
* of list items. The `selectAll` directive renders a checkbox that
* will select/deselect all items in the list.
*
*
* This directive exposes a special object on its local scope called
* `selection` that is used to access the current selection state.
* The following properties on `selection` are available:
*
* | Property | Type | Details |
* |-------------------|-----------------|-------------------------------------------------------------|
* | `selectedItems` | {@type array} | The items that are currently selected |
* | `deselectedItem` | {@type array} | The items that are currently _not_ selected |
* | `isExtended` | {@type boolean} | Indicates that the user has requested an extended selection |
* | `length` | {@type number} | The length of the selected items array |
*
* Use the `multi-select-list` directive to indicate that you want
* to allow users to select items in a list. To display a checkbox
* next to each item, use the {@link multiSelectList.directive:selectListItem `select-list-item`} directive.
*
* # Rendering a basic multi-select list
*
* @example
*
* This example creates a list of names and then
* uses `multiSelectList` to make the names
* selectable:
*
<example module="multiSelectList">
<file name="index.html">
<div ng-init="names =
[ { name: 'blah'
},
{ name: 'diddy'
},
{ name: 'doo'
},
{ name: 'dah'
},
{ name: 'blah'
}
]">
<ul multi-select-list>
<li ng-repeat="item in names">
<select-list-item item="item"></select-list-item>
{{item.name}}
</li>
</ul>
</div>
</file>
</example>
*
*/
import controller from './multi-select-list.controller'; import controller from './multi-select-list.controller';
export default export default
[ function() { [ function() {
return { return {
restrict: 'A', restrict: 'A',
scope: { scope: {
}, },

View File

@@ -1,3 +1,122 @@
/**
* @ngdoc directive
* @name multiSelectList.directive:selectAll
* @scope
* @restrict E
*
* @param {string} label The text that will appear next to the checkbox
* @param {number} itemsLength The number of displayed items in the list
* @param {number} extendedItemsLength The total number of items in the list used for extended mode (see below)
* @param {string_expression} extendedLabel A custom label to display when prompting the user to extend the selection; this is an expression so strings must be in single quotes ('), but you can use scope varibles here to display the count of items with the `extendedItemsLength` property
* @param {boolean_expression} selectionsEmpty An expression that evaluates to a truthy value used to disable
* the select all checkbox when the displayed list is empty
*
* @description
*
* Use the `select-all` directive as a child of a `multi-select-list`
* to present the user with a checkbox that, when checked, checks all
* `select-list-item` children, and when unchecked it unchecks them.
*
* <example module="multiSelectList">
<file name="index.html">
<div ng-init="names =
[ { name: 'blah'
},
{ name: 'diddy'
},
{ name: 'doo'
},
{ name: 'dah'
},
{ name: 'blah'
}
]">
<ul multi-select-list>
<li>
<select-all label="Select All"></select-all>
</li>
<li ng-repeat="item in names">
<select-list-item item="item"></select-list-item>
{{item.name}}
</li>
</ul>
</div>
</file>
* </example>
*
* ## Extended Selections
*
* In some cases the list items you are displaying are only a subset of
* a larger list (eg. using pagination or infinite scroll to seperate
* items). In these cases, when a user checks "select all", it may be
* useful to give them the option to also select all the remaining
* items in the list.
*
* This behavior is controlled by the `extendedItemsLength` property
* of this directive. Set it to the total length of items in the list.
* For example, if you have a list of 100 items, displayed 10 per page,
* then `itemsLength` would be 10 and `extendedItemsLength` would be 100.
* When the user checks "select all" in the above example, it will show
* a button prompting them to "Select all 100 items". When the user selects
* this option, the `select-all` directive tells the `multiSelectList`
* controller that the selection is "extended" to all the items in the list.
* Listeners to the `multiSelectList.selectionChanged` event can then use this
* flag to respond differently when all items are selected.
*
*
* <example module="extendedSelectionExample">
<file name="app.js">
angular.module('extendedSelectionExample', ['multiSelectList'])
.controller('namesController', ['$scope', function($scope) {
var cleanup = $scope.$on('multiSelectList.selectionChanged', function(e, selection) {
$scope.isSelectionExtended = selection.isExtended;
});
$scope.$on('$destroy', cleanup);
$scope.allNames =
[ { name: 'John'
},
{ name: 'Jared'
},
{ name: 'Joe'
},
{ name: 'James'
},
{ name: 'Matt'
},
{ name: 'Luke'
},
{ name: 'Chris'
}
];
$scope.firstPageOfNames =
$scope.allNames.slice(0,3);
}]);
</file>
<file name="index.html">
<div ng-controller="namesController">
<p ng-if="isSelectionExtended">Extended Selection</p>
<ul multi-select-list>
<li>
<select-all
label="Select All"
selections-empty="selectedItems.length === 0"
extended-items-length="allNames.length"
items-length="firstPageOfNames.length"></select-all>
</li>
<li ng-repeat="item in firstPageOfNames">
<select-list-item item="item"></select-list-item>
{{item.name}}
</li>
</ul>
</div>
</file>
*</example>
*/
// TODO: Extract to its own helper // TODO: Extract to its own helper
// Example: // Example:
// template('shared/multi-select-list/select-all') // template('shared/multi-select-list/select-all')
@@ -17,14 +136,14 @@ export default
label: '@', label: '@',
itemsLength: '=', itemsLength: '=',
extendedItemsLength: '=', extendedItemsLength: '=',
isSelectionExtended: '=', extendedLabel: '&',
isSelectionEmpty: '=selectionsEmpty' isSelectionEmpty: '=selectionsEmpty'
}, },
templateUrl: template('shared/multi-select-list/select-all'), templateUrl: template('shared/multi-select-list/select-all'),
link: function(scope, element, attrs, controller) { link: function(scope, element, attrs, controller) {
scope.label = scope.label || 'All'; scope.label = scope.label || 'All';
scope.selectExtendedLabel = scope.extendedLabel || 'Select all ' + scope.extendedItemsLength + ' items'; scope.selectExtendedLabel = scope.extendedLabel() || 'Select all ' + scope.extendedItemsLength + ' items';
scope.deselectExtendedLabel = scope.deselectExtendedLabel || 'Deselect extra items'; scope.deselectExtendedLabel = scope.deselectExtendedLabel || 'Deselect extra items';
scope.doSelectAll = function(e) { scope.doSelectAll = function(e) {
@@ -36,6 +155,12 @@ export default
} }
} else { } else {
controller.deselectAll(); controller.deselectAll();
if (scope.isSelectionExtended) {
scope.deselectAllExtended();
}
scope.showExtendedMessage = false;
} }
}; };
@@ -51,10 +176,12 @@ export default
scope.selectAllExtended = function() { scope.selectAllExtended = function() {
controller.selectAllExtended(scope.extendedItemsLength); controller.selectAllExtended(scope.extendedItemsLength);
scope.isSelectionExtended = true;
}; };
scope.deselectAllExtended = function() { scope.deselectAllExtended = function() {
controller.deselectAllExtended(scope.extendedItemsLength); controller.deselectAllExtended(scope.extendedItemsLength);
scope.isSelectionExtended = false;
}; };
} }

View File

@@ -13,6 +13,6 @@
</button> </button>
<button <button
ng-click="deselectAllExtended()" ng-click="deselectAllExtended()"
ng-if="isSelectionExtended"> ng-if="isSelectionExtended && showExtendedMessage">
{{deselectExtendedLabel}} {{deselectExtendedLabel}}
</button> </button>

View File

@@ -1,3 +1,21 @@
/**
* @ngdoc directive
* @name multiSelectList.directive:selectListItem
* @restrict E
* @scope
* @description
*
The `select-list-item` directive renders a checkbox for tracking
the state of a given item in a list. When the user checks the
checkbox it tells the `multi-select-list` controller to select
the item; when the user unchecks the checkbox it tells the controller
to deselect the item.
@example
For examples of using this directive, see {@link multiSelectList.directive:multiSelectList multiSelectList}.
*/
export default export default
[ function() { [ function() {
return { return {

View File

@@ -3,7 +3,7 @@
*/ */
/** /**
* @ngdoc function * @ngdoc function
* @name widgets.function:DashboardJobs * @name widgets.function:PortalJobs
* @description * @description
* *
*/ */