diff --git a/dist/md-data-table.js b/dist/md-data-table.js index 059af779..b6241c78 100644 --- a/dist/md-data-table.js +++ b/dist/md-data-table.js @@ -104,59 +104,59 @@ function mdBody() { angular.module('md.data.table').directive('mdCell', mdCell); function mdCell() { - + function compile(tElement) { var select = tElement.find('md-select'); - + if(select.length) { select.addClass('md-table-select').attr('md-container-class', 'md-table-select'); } - + tElement.addClass('md-cell'); - + return postLink; } - + // empty controller to be bind properties to in postLink function function Controller() { - + } - + function postLink(scope, element, attrs, ctrls) { var select = element.find('md-select'); var cellCtrl = ctrls.shift(); var tableCtrl = ctrls.shift(); - + if(attrs.ngClick) { element.addClass('md-clickable'); } - + if(select.length) { select.on('click', function (event) { event.stopPropagation(); }); - + element.addClass('md-clickable').on('click', function (event) { event.stopPropagation(); select[0].click(); }); } - + cellCtrl.getTable = tableCtrl.getElement; - + function getColumn() { return tableCtrl.$$columns[getIndex()]; } - + function getIndex() { return Array.prototype.indexOf.call(element.parent().children(), element[0]); } - + scope.$watch(getColumn, function (column) { if(!column) { return; } - + if(column.numeric) { element.addClass('md-numeric'); } else { @@ -164,7 +164,7 @@ function mdCell() { } }); } - + return { controller: Controller, compile: compile, @@ -322,15 +322,15 @@ function controllerDecorator($delegate) { } controllerDecorator.$inject = ['$delegate']; - + function mdEditDialog($compile, $controller, $document, $mdUtil, $q, $rootScope, $templateCache, $templateRequest, $window) { /* jshint validthis: true */ - + var ESCAPE = 27; - + var busy = false; var body = angular.element($document.prop('body')); - + /* * bindToController * controller @@ -348,73 +348,73 @@ function mdEditDialog($compile, $controller, $document, $mdUtil, $q, $rootScope, escToClose: true, focusOnOpen: true }; - + function build(template, options) { var scope = $rootScope.$new(); var element = $compile(template)(scope); var backdrop = $mdUtil.createBackdrop(scope, 'md-edit-dialog-backdrop'); var controller; - + if(options.controller) { controller = getController(options, scope, {$element: element, $scope: scope}); } else { angular.extend(scope, options.scope); } - + if(options.disableScroll) { disableScroll(element); } - + body.prepend(backdrop).append(element.addClass('md-whiteframe-1dp')); - + positionDialog(element, options.target); - - if(options.focusOnOpen) { - focusOnOpen(element); - } - + + if(options.focusOnOpen) { + focusOnOpen(element); + } + if(options.clickOutsideToClose) { backdrop.on('click', function () { element.remove(); }); } - + if(options.escToClose) { escToClose(element); } - + element.on('$destroy', function () { busy = false; backdrop.remove(); }); - + return controller; } - + function disableScroll(element) { var restoreScroll = $mdUtil.disableScrollAround(element, body); - + element.on('$destroy', function () { restoreScroll(); }); } - + function getController(options, scope, inject) { if(!options.controller) { return; } - + if(options.resolve) { angular.extend(inject, options.resolve); } - + if(options.locals) { angular.extend(inject, options.locals); } - + if(options.controllerAs) { scope[options.controllerAs] = {}; - + if(options.bindToController) { angular.extend(scope[options.controllerAs], options.scope); } else { @@ -423,174 +423,174 @@ function mdEditDialog($compile, $controller, $document, $mdUtil, $q, $rootScope, } else { angular.extend(scope, options.scope); } - + if(options.bindToController) { return $controller(options.controller, inject, scope[options.controllerAs]); } else { return $controller(options.controller, inject); } } - + function getTemplate(options) { return $q(function (resolve, reject) { var template = options.template; - + function illegalType(type) { reject('Unexpected template value. Expected a string; received a ' + type + '.'); } - + if(template) { return angular.isString(template) ? resolve(template) : illegalType(typeof template); } - + if(options.templateUrl) { template = $templateCache.get(options.templateUrl); - + if(template) { return resolve(template); } - + var success = function (template) { return resolve(template); }; - + var error = function () { return reject('Error retrieving template from URL.'); }; - + return $templateRequest(options.templateUrl).then(success, error); } - + reject('Template not provided.'); }); } - + function logError(error) { busy = false; console.error(error); } - + function escToClose(element) { var keyup = function (event) { if(event.keyCode === ESCAPE) { element.remove(); } }; - + body.on('keyup', keyup); - + element.on('$destroy', function () { body.off('keyup', keyup); }); } - function focusOnOpen(element) { - $mdUtil.nextTick(function () { + function focusOnOpen(element) { + $mdUtil.nextTick(function () { var autofocus = $mdUtil.findFocusTarget(element); - - if(autofocus) { - autofocus.focus(); - } - }, false); + + if(autofocus) { + autofocus.focus(); + } + }, false); } function positionDialog(element, target) { var table = angular.element(target).controller('mdCell').getTable(); - + var getHeight = function () { return element.prop('clientHeight'); }; - + var getSize = function () { return { width: getWidth(), height: getHeight() }; }; - + var getTableBounds = function () { var parent = table.parent(); - + if(parent.prop('tagName') === 'MD-TABLE-CONTAINER') { return parent[0].getBoundingClientRect(); } else { return table[0].getBoundingClientRect(); } }; - + var getWidth = function () { return element.prop('clientWidth'); }; - + var reposition = function () { var size = getSize(); var cellBounds = target.getBoundingClientRect(); var tableBounds = getTableBounds(); - + if(size.width > tableBounds.right - cellBounds.left) { element.css('left', tableBounds.right - size.width + 'px'); } else { element.css('left', cellBounds.left + 'px'); } - + if(size.height > tableBounds.bottom - cellBounds.top) { element.css('top', tableBounds.bottom - size.height + 'px'); } else { element.css('top', cellBounds.top + 1 + 'px'); } - + element.css('minWidth', cellBounds.width + 'px'); }; - + var watchWidth = $rootScope.$watch(getWidth, reposition); var watchHeight = $rootScope.$watch(getHeight, reposition); - + $window.addEventListener('resize', reposition); - + element.on('$destroy', function () { watchWidth(); watchHeight(); - + $window.removeEventListener('resize', reposition); }); } - + function preset(size, options) { - + function getAttrs() { var attrs = 'type="' + (options.type || 'text') + '"'; - + for(var attr in options.validators) { attrs += ' ' + attr + '="' + options.validators[attr] + '"'; } - + return attrs; } - + return { controller: ['$element', '$q', 'save', '$scope', function ($element, $q, save, $scope) { function update() { if($scope.editDialog.$invalid) { return $q.reject(); } - + if(angular.isFunction(save)) { return $q.when(save($scope.editDialog.input)); } - + return $q.resolve(); } - + this.dismiss = function () { $element.remove(); }; - + this.getInput = function () { return $scope.editDialog.input; }; - + $scope.dismiss = this.dismiss; - + $scope.submit = function () { update().then(function () { $scope.dismiss(); @@ -629,60 +629,60 @@ function mdEditDialog($compile, $controller, $document, $mdUtil, $q, $rootScope, '' }; } - + this.show = function (options) { if(busy) { return $q.reject(); } - + busy = true; options = angular.extend({}, defaultOptions, options); - + if(!options.targetEvent) { return logError('options.targetEvent is required to align the dialog with the table cell.'); } - + if(!options.targetEvent.currentTarget.classList.contains('md-cell')) { return logError('The event target must be a table cell.'); } - + if(options.bindToController && !options.controllerAs) { return logError('You must define options.controllerAs when options.bindToController is true.'); } - + options.target = options.targetEvent.currentTarget; - + var promise = getTemplate(options); var promises = [promise]; - + for(var prop in options.resolve) { promise = options.resolve[prop]; promises.push($q.when(angular.isFunction(promise) ? promise() : promise)); } - + promise = $q.all(promises); - + promise['catch'](logError); - + return promise.then(function (results) { var template = results.shift(); - + for(var prop in options.resolve) { options.resolve[prop] = results.shift(); } - + return build(template, options); }); }; - + this.small = function (options) { return this.show(angular.extend({}, options, preset('small', options))); }.bind(this); - + this.large = function (options) { return this.show(angular.extend({}, options, preset('large', options))); }.bind(this); - + return this; } @@ -711,24 +711,24 @@ function mdHead($compile) { tElement.addClass('md-head'); return postLink; } - + // empty controller to be bind scope properties to function Controller() { - + } - + function postLink(scope, element, attrs, tableCtrl) { // because scope.$watch is unpredictable var oldValue = new Array(2); - + function addCheckboxColumn() { element.children().prepend(''); } - + function attatchCheckbox() { element.prop('lastElementChild').firstElementChild.appendChild($compile(createCheckBox())(scope)[0]); } - + function createCheckBox() { return angular.element('').attr({ 'aria-label': 'Select All', @@ -737,68 +737,82 @@ function mdHead($compile) { 'ng-disabled': '!getSelectableRows().length' }); } - + function detachCheckbox() { var cell = element.prop('lastElementChild').firstElementChild; - + if(cell.classList.contains('md-checkbox-column')) { angular.element(cell).empty(); } } - + function enableRowSelection() { return tableCtrl.$$rowSelect; } - + function mdSelectCtrl(row) { return angular.element(row).controller('mdSelect'); } - + function removeCheckboxColumn() { Array.prototype.some.call(element.find('th'), function (cell) { return cell.classList.contains('md-checkbox-column') && cell.remove(); }); } - + scope.allSelected = function () { var rows = scope.getSelectableRows(); - return rows.length && rows.every(function (row) { return row.isSelected(); }); }; - + scope.getSelectableRows = function () { return tableCtrl.getBodyRows().map(mdSelectCtrl).filter(function (ctrl) { return ctrl && !ctrl.disabled; }); }; - - scope.selectAll = function () { - tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { - if(ctrl && !ctrl.isSelected()) { - ctrl.select(); + + + /* + Updated this function + - to select all rows if the md-select-all attribute is visible and contains an array of ojects + - if md-select-all is undefined function will default to its orignal behaviour "select on rows on page" + */ + scope.selectAll = function () { + tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { + if (ctrl.model_allRows) { + ctrl.selectAll(); + }else if(ctrl && !ctrl.isSelected()) { + ctrl.select(); } }); }; - + scope.toggleAll = function () { return scope.allSelected() ? scope.unSelectAll() : scope.selectAll(); }; - - scope.unSelectAll = function () { - tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { - if(ctrl && ctrl.isSelected()) { - ctrl.deselect(); + + /* + Updated this function + - to deselect all rows if the md-select-all attribute is visible and contains an array of ojects + - if md-select-all is undefined function will default to its orignal behaviour "select on rows on page" + */ + scope.unSelectAll = function () { + tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { + if (ctrl.model_allRows) { + ctrl.deselectAll(); + }else if(ctrl && ctrl.isSelected()) { + ctrl.deselect(); } }); }; - + scope.$watchGroup([enableRowSelection, tableCtrl.enableMultiSelect], function (newValue) { if(newValue[0] !== oldValue[0]) { if(newValue[0]) { addCheckboxColumn(); - + if(newValue[1]) { attatchCheckbox(); } @@ -812,11 +826,11 @@ function mdHead($compile) { detachCheckbox(); } } - + angular.copy(newValue, oldValue); }); } - + return { bindToController: true, compile: compile, @@ -841,23 +855,27 @@ function mdRow() { tElement.addClass('md-row'); return postLink; } - + function postLink(scope, element, attrs, tableCtrl) { function enableRowSelection() { return tableCtrl.$$rowSelect; } - + function isBodyRow() { return tableCtrl.getBodyRows().indexOf(element[0]) !== -1; } - + + function isAllRows() { + return scope.mdSelectAll; + } + function isChild(node) { return element[0].contains(node[0]); } - + if(isBodyRow()) { var cell = angular.element(''); - + scope.$watch(enableRowSelection, function (enable) { // if a row is not selectable, prepend an empty cell to it if(enable && !attrs.mdSelect) { @@ -866,7 +884,7 @@ function mdRow() { } return; } - + if(isChild(cell)) { cell.remove(); } @@ -883,11 +901,14 @@ function mdRow() { angular.module('md.data.table').directive('mdSelect', mdSelect); -function mdSelect($compile, $parse) { +function mdSelect($compile, $parse, $filter) { // empty controller to bind scope properties to - function Controller() { - + function Controller() { + //Added this function which returns filtered array of objects + this.searchResults = function (data, searchText) { + return $filter('filter')(data, searchText); + } } function postLink(scope, element, attrs, ctrls) { @@ -895,7 +916,17 @@ function mdSelect($compile, $parse) { var tableCtrl = ctrls.shift(); var getId = $parse(attrs.mdSelectId); + self.id = getId(self.model); + /* + Added this function which + - returns filtered arrary of object from the searchResults function + - based on the list(json object) passed from the md-select-all atttribute + - and filters the list based on the text passed from the md-search atttribute + */ + self.data = function () { + return self.searchResults(self.model_allRows, self.search); + } if(tableCtrl.$$rowSelect && self.id) { if(tableCtrl.$$hash.has(self.id)) { @@ -925,8 +956,9 @@ function mdSelect($compile, $parse) { }); } } - - self.isSelected = function () { + + //Added this opitional object argument when passed isSelected returns a boolean value based on the argument + self.isSelected = function (model) { if(!tableCtrl.$$rowSelect) { return false; } @@ -935,16 +967,18 @@ function mdSelect($compile, $parse) { return tableCtrl.$$hash.has(self.id); } + if (model) { + return tableCtrl.selected.indexOf(model) !== -1; + } return tableCtrl.selected.indexOf(self.model) !== -1; - }; + }; self.select = function () { if(self.disabled) { return; } - - if(tableCtrl.enableMultiSelect()) { - tableCtrl.selected.push(self.model); + if (tableCtrl.enableMultiSelect()) { + tableCtrl.selected.push(self.model); } else { tableCtrl.selected.splice(0, tableCtrl.selected.length, self.model); } @@ -953,6 +987,44 @@ function mdSelect($compile, $parse) { self.onSelect(self.model); } }; + + /* + Added this function which + - will select rows based on the array of objects returned from the data function + - will select all rows if the are not selected + */ + self.selectAll = function () { + if (self.disabled) { + return; + } + if (tableCtrl.enableMultiSelect()) { + self.deselectAll(); + angular.forEach(self.data(), function (model, key) { + if (!self.isSelected(model)) { + tableCtrl.selected.push(model); + } + }); + } else { + tableCtrl.selected.splice(0, tableCtrl.selected.length, self.data()); + } + + if (angular.isFunction(self.onSelect)) { + self.onSelect(self.data()); + } + } + /* + Added this function which + - will deselect rows based on the array of objects returned from the data function + - will deselect all rows if the are selected + */ + self.deselectAll = function () { + angular.forEach(self.data(), function (model, index) { + if (self.isSelected(model)) + { + tableCtrl.selected.splice(tableCtrl.selected.indexOf(model), 1); + } + }); + } self.deselect = function () { if(self.disabled) { @@ -1087,18 +1159,20 @@ function mdSelect($compile, $parse) { disabled: '=ngDisabled', onSelect: '=?mdOnSelect', onDeselect: '=?mdOnDeselect', - autoSelect: '=mdAutoSelect' + autoSelect: '=mdAutoSelect', + model_allRows: '=mdSelectAll', + search: '=mdSearch' } }; } -mdSelect.$inject = ['$compile', '$parse']; +mdSelect.$inject = ['$compile', '$parse','$filter']; angular.module('md.data.table').directive('mdTable', mdTable); function Hash() { var keys = {}; - + this.equals = function (key, item) { return keys[key] === item; }; @@ -1106,7 +1180,7 @@ function Hash() { this.get = function (key) { return keys[key]; }; - + this.has = function (key) { return keys.hasOwnProperty(key); }; @@ -1114,145 +1188,145 @@ function Hash() { this.purge = function (key) { delete keys[key]; }; - + this.update = function (key, item) { keys[key] = item; }; } function mdTable() { - + function compile(tElement, tAttrs) { tElement.addClass('md-table'); - + if(tAttrs.hasOwnProperty('mdProgress')) { var body = tElement.find('tbody')[0]; var progress = angular.element(''); - + if(body) { tElement[0].insertBefore(progress[0], body); } } } - + function Controller($attrs, $element, $q, $scope) { var self = this; var queue = []; var watchListener; var modelChangeListeners = []; - + self.$$hash = new Hash(); self.$$columns = {}; - + function enableRowSelection() { self.$$rowSelect = true; - + watchListener = $scope.$watchCollection('$mdTable.selected', function (selected) { modelChangeListeners.forEach(function (listener) { listener(selected); }); }); - + $element.addClass('md-row-select'); } - + function disableRowSelection() { self.$$rowSelect = false; - + if(angular.isFunction(watchListener)) { watchListener(); } - + $element.removeClass('md-row-select'); } - + function resolvePromises() { if(!queue.length) { return $scope.$applyAsync(); } - + queue[0]['finally'](function () { queue.shift(); resolvePromises(); }); } - + function rowSelect() { return $attrs.mdRowSelect === '' || self.rowSelect; } - + function validateModel() { if(!self.selected) { return console.error('Row selection: ngModel is not defined.'); } - + if(!angular.isArray(self.selected)) { return console.error('Row selection: Expected an array. Recived ' + typeof self.selected + '.'); } - + return true; } - + self.columnCount = function () { return self.getRows($element[0]).reduce(function (count, row) { return row.cells.length > count ? row.cells.length : count; }, 0); }; - + self.getRows = function (element) { - return Array.prototype.filter.call(element.rows, function (row) { + return Array.prototype.filter.call(element.rows, function (row) { return !row.classList.contains('ng-leave'); }); }; - + self.getBodyRows = function () { return Array.prototype.reduce.call($element.prop('tBodies'), function (result, tbody) { return result.concat(self.getRows(tbody)); }, []); }; - + self.getElement = function () { return $element; }; - + self.getHeaderRows = function () { return self.getRows($element.prop('tHead')); }; - + self.enableMultiSelect = function () { return $attrs.multiple === '' || $scope.$eval($attrs.multiple); }; - + self.waitingOnPromise = function () { return !!queue.length; }; - + self.queuePromise = function (promise) { if(!promise) { return; } - + if(queue.push(angular.isArray(promise) ? $q.all(promise) : $q.when(promise)) === 1) { resolvePromises(); } }; - + self.registerModelChangeListener = function (listener) { modelChangeListeners.push(listener); }; - + self.removeModelChangeListener = function (listener) { var index = modelChangeListeners.indexOf(listener); - + if(index !== -1) { modelChangeListeners.splice(index, 1); } }; - + if($attrs.hasOwnProperty('mdProgress')) { $scope.$watch('$mdTable.progress', self.queuePromise); } - + $scope.$watch(rowSelect, function (enable) { if(enable && !!validateModel()) { enableRowSelection(); @@ -1261,9 +1335,9 @@ function mdTable() { } }); } - + Controller.$inject = ['$attrs', '$element', '$q', '$scope']; - + return { bindToController: true, compile: compile, @@ -1483,4 +1557,4 @@ function virtualPageSelect() { }; } -})(window, angular); \ No newline at end of file +})(window, angular); diff --git a/src/scripts/mdHead.js b/src/scripts/mdHead.js index 30984cb5..2a70c135 100644 --- a/src/scripts/mdHead.js +++ b/src/scripts/mdHead.js @@ -8,24 +8,24 @@ function mdHead($compile) { tElement.addClass('md-head'); return postLink; } - + // empty controller to be bind scope properties to function Controller() { - + } - + function postLink(scope, element, attrs, tableCtrl) { // because scope.$watch is unpredictable var oldValue = new Array(2); - + function addCheckboxColumn() { element.children().prepend(''); } - + function attatchCheckbox() { element.prop('lastElementChild').firstElementChild.appendChild($compile(createCheckBox())(scope)[0]); } - + function createCheckBox() { return angular.element('').attr({ 'aria-label': 'Select All', @@ -34,68 +34,82 @@ function mdHead($compile) { 'ng-disabled': '!getSelectableRows().length' }); } - + function detachCheckbox() { var cell = element.prop('lastElementChild').firstElementChild; - + if(cell.classList.contains('md-checkbox-column')) { angular.element(cell).empty(); } } - + function enableRowSelection() { return tableCtrl.$$rowSelect; } - + function mdSelectCtrl(row) { return angular.element(row).controller('mdSelect'); } - + function removeCheckboxColumn() { Array.prototype.some.call(element.find('th'), function (cell) { return cell.classList.contains('md-checkbox-column') && cell.remove(); }); } - + scope.allSelected = function () { var rows = scope.getSelectableRows(); - return rows.length && rows.every(function (row) { return row.isSelected(); }); }; - + scope.getSelectableRows = function () { return tableCtrl.getBodyRows().map(mdSelectCtrl).filter(function (ctrl) { return ctrl && !ctrl.disabled; }); }; - - scope.selectAll = function () { - tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { - if(ctrl && !ctrl.isSelected()) { - ctrl.select(); + + + /* + Updated this function + - to select all rows if the md-select-all attribute is visible and contains an array of ojects + - if md-select-all is undefined function will default to its orignal behaviour "select on rows on page" + */ + scope.selectAll = function () { + tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { + if (ctrl.model_allRows) { + ctrl.selectAll(); + }else if(ctrl && !ctrl.isSelected()) { + ctrl.select(); } }); }; - + scope.toggleAll = function () { return scope.allSelected() ? scope.unSelectAll() : scope.selectAll(); }; - - scope.unSelectAll = function () { - tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { - if(ctrl && ctrl.isSelected()) { - ctrl.deselect(); + + /* + Updated this function + - to deselect all rows if the md-select-all attribute is visible and contains an array of ojects + - if md-select-all is undefined function will default to its orignal behaviour "select on rows on page" + */ + scope.unSelectAll = function () { + tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { + if (ctrl.model_allRows) { + ctrl.deselectAll(); + }else if(ctrl && ctrl.isSelected()) { + ctrl.deselect(); } }); }; - + scope.$watchGroup([enableRowSelection, tableCtrl.enableMultiSelect], function (newValue) { if(newValue[0] !== oldValue[0]) { if(newValue[0]) { addCheckboxColumn(); - + if(newValue[1]) { attatchCheckbox(); } @@ -109,11 +123,11 @@ function mdHead($compile) { detachCheckbox(); } } - + angular.copy(newValue, oldValue); }); } - + return { bindToController: true, compile: compile, diff --git a/src/scripts/mdSelect.js b/src/scripts/mdSelect.js index 88ffda98..cc159d4a 100644 --- a/src/scripts/mdSelect.js +++ b/src/scripts/mdSelect.js @@ -2,11 +2,14 @@ angular.module('md.data.table').directive('mdSelect', mdSelect); -function mdSelect($compile, $parse) { +function mdSelect($compile, $parse, $filter) { // empty controller to bind scope properties to - function Controller() { - + function Controller() { + //Added this function which returns filtered array of objects + this.searchResults = function (data, searchText) { + return $filter('filter')(data, searchText); + } } function postLink(scope, element, attrs, ctrls) { @@ -14,7 +17,17 @@ function mdSelect($compile, $parse) { var tableCtrl = ctrls.shift(); var getId = $parse(attrs.mdSelectId); + self.id = getId(self.model); + /* + Added this function which + - returns filtered arrary of object from the searchResults function + - based on the list(json object) passed from the md-select-all atttribute + - and filters the list based on the text passed from the md-search atttribute + */ + self.data = function () { + return self.searchResults(self.model_allRows, self.search); + } if(tableCtrl.$$rowSelect && self.id) { if(tableCtrl.$$hash.has(self.id)) { @@ -44,8 +57,9 @@ function mdSelect($compile, $parse) { }); } } - - self.isSelected = function () { + + //Added this opitional object argument when passed isSelected returns a boolean value based on the argument + self.isSelected = function (model) { if(!tableCtrl.$$rowSelect) { return false; } @@ -54,16 +68,18 @@ function mdSelect($compile, $parse) { return tableCtrl.$$hash.has(self.id); } + if (model) { + return tableCtrl.selected.indexOf(model) !== -1; + } return tableCtrl.selected.indexOf(self.model) !== -1; - }; + }; self.select = function () { if(self.disabled) { return; } - - if(tableCtrl.enableMultiSelect()) { - tableCtrl.selected.push(self.model); + if (tableCtrl.enableMultiSelect()) { + tableCtrl.selected.push(self.model); } else { tableCtrl.selected.splice(0, tableCtrl.selected.length, self.model); } @@ -72,6 +88,44 @@ function mdSelect($compile, $parse) { self.onSelect(self.model); } }; + + /* + Added this function which + - will select rows based on the array of objects returned from the data function + - will select all rows if the are not selected + */ + self.selectAll = function () { + if (self.disabled) { + return; + } + if (tableCtrl.enableMultiSelect()) { + self.deselectAll(); + angular.forEach(self.data(), function (model, key) { + if (!self.isSelected(model)) { + tableCtrl.selected.push(model); + } + }); + } else { + tableCtrl.selected.splice(0, tableCtrl.selected.length, self.data()); + } + + if (angular.isFunction(self.onSelect)) { + self.onSelect(self.data()); + } + } + /* + Added this function which + - will deselect rows based on the array of objects returned from the data function + - will deselect all rows if the are selected + */ + self.deselectAll = function () { + angular.forEach(self.data(), function (model, index) { + if (self.isSelected(model)) + { + tableCtrl.selected.splice(tableCtrl.selected.indexOf(model), 1); + } + }); + } self.deselect = function () { if(self.disabled) { @@ -206,9 +260,11 @@ function mdSelect($compile, $parse) { disabled: '=ngDisabled', onSelect: '=?mdOnSelect', onDeselect: '=?mdOnDeselect', - autoSelect: '=mdAutoSelect' + autoSelect: '=mdAutoSelect', + model_allRows: '=mdSelectAll', + search: '=mdSearch' } }; } -mdSelect.$inject = ['$compile', '$parse']; \ No newline at end of file +mdSelect.$inject = ['$compile', '$parse','$filter']; \ No newline at end of file diff --git a/src/scripts/mdTable.js b/src/scripts/mdTable.js index 6b1f9635..5f96ccdc 100644 --- a/src/scripts/mdTable.js +++ b/src/scripts/mdTable.js @@ -4,7 +4,7 @@ angular.module('md.data.table').directive('mdTable', mdTable); function Hash() { var keys = {}; - + this.equals = function (key, item) { return keys[key] === item; }; @@ -12,7 +12,7 @@ function Hash() { this.get = function (key) { return keys[key]; }; - + this.has = function (key) { return keys.hasOwnProperty(key); }; @@ -20,13 +20,169 @@ function Hash() { this.purge = function (key) { delete keys[key]; }; - + this.update = function (key, item) { keys[key] = item; }; } function mdTable() { + + function compile(tElement, tAttrs) { + tElement.addClass('md-table'); + + if(tAttrs.hasOwnProperty('mdProgress')) { + var body = tElement.find('tbody')[0]; + var progress = angular.element(''); + + if(body) { + tElement[0].insertBefore(progress[0], body); + } + } + } + + function Controller($attrs, $element, $q, $scope) { + var self = this; + var queue = []; + var watchListener; + var modelChangeListeners = []; + + self.$$hash = new Hash(); + self.$$columns = {}; + + function enableRowSelection() { + self.$$rowSelect = true; + + watchListener = $scope.$watchCollection('$mdTable.selected', function (selected) { + modelChangeListeners.forEach(function (listener) { + listener(selected); + }); + }); + + $element.addClass('md-row-select'); + } + + function disableRowSelection() { + self.$$rowSelect = false; + + if(angular.isFunction(watchListener)) { + watchListener(); + } + + $element.removeClass('md-row-select'); + } + + function resolvePromises() { + if(!queue.length) { + return $scope.$applyAsync(); + } + + queue[0]['finally'](function () { + queue.shift(); + resolvePromises(); + }); + } + + function rowSelect() { + return $attrs.mdRowSelect === '' || self.rowSelect; + } + + function validateModel() { + if(!self.selected) { + return console.error('Row selection: ngModel is not defined.'); + } + + if(!angular.isArray(self.selected)) { + return console.error('Row selection: Expected an array. Recived ' + typeof self.selected + '.'); + } + + return true; + } + + self.columnCount = function () { + return self.getRows($element[0]).reduce(function (count, row) { + return row.cells.length > count ? row.cells.length : count; + }, 0); + }; + + self.getRows = function (element) { + return Array.prototype.filter.call(element.rows, function (row) { + return !row.classList.contains('ng-leave'); + }); + }; + + self.getBodyRows = function () { + return Array.prototype.reduce.call($element.prop('tBodies'), function (result, tbody) { + return result.concat(self.getRows(tbody)); + }, []); + }; + + self.getElement = function () { + return $element; + }; + + self.getHeaderRows = function () { + return self.getRows($element.prop('tHead')); + }; + + self.enableMultiSelect = function () { + return $attrs.multiple === '' || $scope.$eval($attrs.multiple); + }; + + self.waitingOnPromise = function () { + return !!queue.length; + }; + + self.queuePromise = function (promise) { + if(!promise) { + return; + } + + if(queue.push(angular.isArray(promise) ? $q.all(promise) : $q.when(promise)) === 1) { + resolvePromises(); + } + }; + + self.registerModelChangeListener = function (listener) { + modelChangeListeners.push(listener); + }; + + self.removeModelChangeListener = function (listener) { + var index = modelChangeListeners.indexOf(listener); + + if(index !== -1) { + modelChangeListeners.splice(index, 1); + } + }; + + if($attrs.hasOwnProperty('mdProgress')) { + $scope.$watch('$mdTable.progress', self.queuePromise); + } + + $scope.$watch(rowSelect, function (enable) { + if(enable && !!validateModel()) { + enableRowSelection(); + } else { + disableRowSelection(); + } + }); + } + + Controller.$inject = ['$attrs', '$element', '$q', '$scope']; + + return { + bindToController: true, + compile: compile, + controller: Controller, + controllerAs: '$mdTable', + restrict: 'A', + scope: { + progress: '=?mdProgress', + selected: '=ngModel', + rowSelect: '=mdRowSelect' + } + }; +} function compile(tElement, tAttrs) { tElement.addClass('md-table');