diff --git a/bower.json b/bower.json index 100ae0e4..793373a5 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "smart-table", - "version": "1.4.8", + "version": "1.4.9", "homepage": "https://github.com/lorenzofox3/Smart-Table", "authors": [ "lorenzofox3 " diff --git a/changeLog.md b/changeLog.md index 79f5f830..596d86c3 100644 --- a/changeLog.md +++ b/changeLog.md @@ -88,4 +88,8 @@ function(tableState, tableController){ ## version 1.4.8 -* fix 281 +* fix #281 + +## version 1.4.9 + +* fix #285 diff --git a/dist/smart-table.debug.js b/dist/smart-table.debug.js index b20e9833..bb453d39 100644 --- a/dist/smart-table.debug.js +++ b/dist/smart-table.debug.js @@ -1,5 +1,5 @@ /** -* @version 1.4.8 +* @version 1.4.9 * @license MIT */ (function (ng, undefined){ @@ -14,184 +14,191 @@ ng.module('smart-table', []).run(['$templateCache', function ($templateCache) { ng.module('smart-table') - .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController($scope, $parse, $filter, $attrs) { - var propertyName = $attrs.stTable; - var displayGetter = $parse(propertyName); - var displaySetter = displayGetter.assign; - var safeGetter; - var orderBy = $filter('orderBy'); - var filter = $filter('filter'); - var safeCopy = copyRefs(displayGetter($scope)); - var tableState = { - sort: {}, - search: {}, - pagination: { - start: 0 - } - }; - var pipeAfterSafeCopy = true; - var ctrl = this; - var lastSelected; + .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController($scope, $parse, $filter, $attrs) { + var propertyName = $attrs.stTable; + var displayGetter = $parse(propertyName); + var displaySetter = displayGetter.assign; + var safeGetter; + var orderBy = $filter('orderBy'); + var filter = $filter('filter'); + var safeCopy = copyRefs(displayGetter($scope)); + var tableState = { + sort: {}, + search: {}, + pagination: { + start: 0 + } + }; + var pipeAfterSafeCopy = true; + var ctrl = this; + var lastSelected; + + function copyRefs(src) { + return src ? [].concat(src) : []; + } + + function updateSafeCopy() { + safeCopy = copyRefs(safeGetter($scope)); + if (pipeAfterSafeCopy === true) { + ctrl.pipe(); + } + } - function copyRefs(src) { - return src ? [].concat(src) : []; - } + if ($attrs.stSafeSrc) { + safeGetter = $parse($attrs.stSafeSrc); + $scope.$watch(function () { + var safeSrc = safeGetter($scope); + return safeSrc ? safeSrc.length : 0; - function updateSafeCopy() { - safeCopy = copyRefs(safeGetter($scope)); - if (pipeAfterSafeCopy === true) { - ctrl.pipe(); - } + }, function (newValue, oldValue) { + if (newValue !== safeCopy.length) { + updateSafeCopy(); } - - if ($attrs.stSafeSrc) { - safeGetter = $parse($attrs.stSafeSrc); - $scope.$watch(function () { - var safeSrc = safeGetter($scope); - return safeSrc ? safeSrc.length : 0; - - }, function (newValue, oldValue) { - if (newValue !== safeCopy.length) { - updateSafeCopy(); - } - }); - $scope.$watch(function () { - return safeGetter($scope); - }, function (newValue, oldValue) { - if (newValue !== oldValue) { - updateSafeCopy(); - } - }); + }); + $scope.$watch(function () { + return safeGetter($scope); + }, function (newValue, oldValue) { + if (newValue !== oldValue) { + updateSafeCopy(); } + }); + } + + /** + * sort the rows + * @param {Function | String} predicate - function or string which will be used as predicate for the sorting + * @param [reverse] - if you want to reverse the order + */ + this.sortBy = function sortBy(predicate, reverse) { + tableState.sort.predicate = predicate; + tableState.sort.reverse = reverse === true; + + if (ng.isFunction(predicate)) { + tableState.sort.functionName = predicate.name; + } else { + delete tableState.sort.functionName; + } - /** - * sort the rows - * @param {Function | String} predicate - function or string which will be used as predicate for the sorting - * @param [reverse] - if you want to reverse the order - */ - this.sortBy = function sortBy(predicate, reverse) { - tableState.sort.predicate = predicate; - tableState.sort.reverse = reverse === true; - tableState.pagination.start = 0; - return this.pipe(); - }; + tableState.pagination.start = 0; + return this.pipe(); + }; - /** - * search matching rows - * @param {String} input - the input string - * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties - */ - this.search = function search(input, predicate) { - var predicateObject = tableState.search.predicateObject || {}; - var prop = predicate ? predicate : '$'; - predicateObject[prop] = input; - // to avoid to filter out null value - if (!input) { - delete predicateObject[prop]; - } - tableState.search.predicateObject = predicateObject; - tableState.pagination.start = 0; - return this.pipe(); - }; + /** + * search matching rows + * @param {String} input - the input string + * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties + */ + this.search = function search(input, predicate) { + var predicateObject = tableState.search.predicateObject || {}; + var prop = predicate ? predicate : '$'; + predicateObject[prop] = input; + // to avoid to filter out null value + if (!input) { + delete predicateObject[prop]; + } + tableState.search.predicateObject = predicateObject; + tableState.pagination.start = 0; + return this.pipe(); + }; - /** - * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect) - */ - this.pipe = function pipe() { - var pagination = tableState.pagination; - var filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy; - if (tableState.sort.predicate) { - filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse); - } - if (pagination.number !== undefined) { - pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1; - pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start; - filtered = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number)); - } - displaySetter($scope, filtered); - }; + /** + * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect) + */ + this.pipe = function pipe() { + var pagination = tableState.pagination; + var filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy; + if (tableState.sort.predicate) { + filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse); + } + if (pagination.number !== undefined) { + pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1; + pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start; + filtered = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number)); + } + displaySetter($scope, filtered); + }; - /** - * select a dataRow (it will add the attribute isSelected to the row object) - * @param {Object} row - the row to select - * @param {String} [mode] - "single" or "multiple" (multiple by default) - */ - this.select = function select(row, mode) { - var rows = safeCopy; - var index = rows.indexOf(row); - if (index !== -1) { - if (mode === 'single') { - row.isSelected = row.isSelected !== true; - if (lastSelected) { - lastSelected.isSelected = false; - } - lastSelected = row.isSelected === true ? row : undefined; - } else { - rows[index].isSelected = !rows[index].isSelected; - } - } - }; + /** + * select a dataRow (it will add the attribute isSelected to the row object) + * @param {Object} row - the row to select + * @param {String} [mode] - "single" or "multiple" (multiple by default) + */ + this.select = function select(row, mode) { + var rows = safeCopy; + var index = rows.indexOf(row); + if (index !== -1) { + if (mode === 'single') { + row.isSelected = row.isSelected !== true; + if (lastSelected) { + lastSelected.isSelected = false; + } + lastSelected = row.isSelected === true ? row : undefined; + } else { + rows[index].isSelected = !rows[index].isSelected; + } + } + }; - /** - * take a slice of the current sorted/filtered collection (pagination) - * - * @param {Number} start - start index of the slice - * @param {Number} number - the number of item in the slice - */ - this.slice = function splice(start, number) { - tableState.pagination.start = start; - tableState.pagination.number = number; - return this.pipe(); - }; + /** + * take a slice of the current sorted/filtered collection (pagination) + * + * @param {Number} start - start index of the slice + * @param {Number} number - the number of item in the slice + */ + this.slice = function splice(start, number) { + tableState.pagination.start = start; + tableState.pagination.number = number; + return this.pipe(); + }; - /** - * return the current state of the table - * @returns {{sort: {}, search: {}, pagination: {start: number}}} - */ - this.tableState = function getTableState() { - return tableState; - }; + /** + * return the current state of the table + * @returns {{sort: {}, search: {}, pagination: {start: number}}} + */ + this.tableState = function getTableState() { + return tableState; + }; - /** - * Use a different filter function than the angular FilterFilter - * @param filterName the name under which the custom filter is registered - */ - this.setFilterFunction = function setFilterFunction(filterName) { - filter = $filter(filterName); - }; + /** + * Use a different filter function than the angular FilterFilter + * @param filterName the name under which the custom filter is registered + */ + this.setFilterFunction = function setFilterFunction(filterName) { + filter = $filter(filterName); + }; - /** - *User a different function than the angular orderBy - * @param sortFunctionName the name under which the custom order function is registered - */ - this.setSortFunction = function setSortFunction(sortFunctionName) { - orderBy = $filter(sortFunctionName); - }; + /** + *User a different function than the angular orderBy + * @param sortFunctionName the name under which the custom order function is registered + */ + this.setSortFunction = function setSortFunction(sortFunctionName) { + orderBy = $filter(sortFunctionName); + }; - /** - * Usually when the safe copy is updated the pipe function is called. - * Calling this method will prevent it, which is something required when using a custom pipe function - */ - this.preventPipeOnWatch = function preventPipe() { - pipeAfterSafeCopy = false; - }; - }]) - .directive('stTable', function () { - return { - restrict: 'A', - controller: 'stTableController', - link: function (scope, element, attr, ctrl) { + /** + * Usually when the safe copy is updated the pipe function is called. + * Calling this method will prevent it, which is something required when using a custom pipe function + */ + this.preventPipeOnWatch = function preventPipe() { + pipeAfterSafeCopy = false; + }; + }]) + .directive('stTable', function () { + return { + restrict: 'A', + controller: 'stTableController', + link: function (scope, element, attr, ctrl) { - if (attr.stSetFilter) { - ctrl.setFilterFunction(attr.stSetFilter); - } + if (attr.stSetFilter) { + ctrl.setFilterFunction(attr.stSetFilter); + } - if (attr.stSetSort) { - ctrl.setSortFunction(attr.stSetSort); - } - } - }; - }); + if (attr.stSetSort) { + ctrl.setSortFunction(attr.stSetSort); + } + } + }; + }); ng.module('smart-table') .directive('stSearch', ['$timeout', function ($timeout) { diff --git a/dist/smart-table.min.js b/dist/smart-table.min.js index a0c2b35d..041a0a04 100644 --- a/dist/smart-table.min.js +++ b/dist/smart-table.min.js @@ -1,5 +1,5 @@ /** -* @version 1.4.8 +* @version 1.4.9 * @license MIT */ -!function(t,e){"use strict";t.module("smart-table",[]).run(["$templateCache",function(t){t.put("template/smart-table/pagination.html",'')}]),t.module("smart-table").controller("stTableController",["$scope","$parse","$filter","$attrs",function(t,a,s,n){function r(t){return t?[].concat(t):[]}function i(){d=r(c(t)),m===!0&&b.pipe()}var c,l,o=n.stTable,u=a(o),p=u.assign,g=s("orderBy"),f=s("filter"),d=r(u(t)),h={sort:{},search:{},pagination:{start:0}},m=!0,b=this;n.stSafeSrc&&(c=a(n.stSafeSrc),t.$watch(function(){var e=c(t);return e?e.length:0},function(t){t!==d.length&&i()}),t.$watch(function(){return c(t)},function(t,e){t!==e&&i()})),this.sortBy=function(t,e){return h.sort.predicate=t,h.sort.reverse=e===!0,h.pagination.start=0,this.pipe()},this.search=function(t,e){var a=h.search.predicateObject||{},s=e?e:"$";return a[s]=t,t||delete a[s],h.search.predicateObject=a,h.pagination.start=0,this.pipe()},this.pipe=function(){var a=h.pagination,s=h.search.predicateObject?f(d,h.search.predicateObject):d;h.sort.predicate&&(s=g(s,h.sort.predicate,h.sort.reverse)),a.number!==e&&(a.numberOfPages=s.length>0?Math.ceil(s.length/a.number):1,a.start=a.start>=s.length?(a.numberOfPages-1)*a.number:a.start,s=s.slice(a.start,a.start+parseInt(a.number))),p(t,s)},this.select=function(t,a){var s=d,n=s.indexOf(t);-1!==n&&("single"===a?(t.isSelected=t.isSelected!==!0,l&&(l.isSelected=!1),l=t.isSelected===!0?t:e):s[n].isSelected=!s[n].isSelected)},this.slice=function(t,e){return h.pagination.start=t,h.pagination.number=e,this.pipe()},this.tableState=function(){return h},this.setFilterFunction=function(t){f=s(t)},this.setSortFunction=function(t){g=s(t)},this.preventPipeOnWatch=function(){m=!1}}]).directive("stTable",function(){return{restrict:"A",controller:"stTableController",link:function(t,e,a,s){a.stSetFilter&&s.setFilterFunction(a.stSetFilter),a.stSetSort&&s.setSortFunction(a.stSetSort)}}}),t.module("smart-table").directive("stSearch",["$timeout",function(t){return{require:"^stTable",scope:{predicate:"=?stSearch"},link:function(e,a,s,n){var r=n,i=null,c=s.stDelay||400;e.$watch("predicate",function(t,e){t!==e&&(n.tableState().search={},r.search(a[0].value||"",t))}),e.$watch(function(){return n.tableState().search},function(t){var s=e.predicate||"$";t.predicateObject&&t.predicateObject[s]!==a[0].value&&(a[0].value=t.predicateObject[s]||"")},!0),a.bind("input",function(a){a=a.originalEvent||a,null!==i&&t.cancel(i),i=t(function(){r.search(a.target.value,e.predicate||""),i=null},c)})}}}]),t.module("smart-table").directive("stSelectRow",function(){return{restrict:"A",require:"^stTable",scope:{row:"=stSelectRow"},link:function(t,e,a,s){var n=a.stSelectMode||"single";e.bind("click",function(){t.$apply(function(){s.select(t.row,n)})}),t.$watch("row.isSelected",function(t){t===!0?e.addClass("st-selected"):e.removeClass("st-selected")})}}}),t.module("smart-table").directive("stSort",["$parse",function(a){return{restrict:"A",require:"^stTable",link:function(s,n,r,i){function c(){p++,o=t.isFunction(u(s))?u(s):r.stSort,p%3===0&&r.stSkipNatural===e?(p=0,i.tableState().sort={},i.tableState().pagination.start=0,i.pipe()):i.sortBy(o,p%2===0)}var l,o=r.stSort,u=a(o),p=0,g=r.stClassAscent||"st-sort-ascent",f=r.stClassDescent||"st-sort-descent",d=[g,f];r.stSortDefault&&(l=s.$eval(r.stSortDefault)!==e?s.$eval(r.stSortDefault):r.stSortDefault),n.bind("click",function(){o&&s.$apply(c)}),l&&(p="reverse"===r.stSortDefault?1:0,c()),s.$watch(function(){return i.tableState().sort},function(t){t.predicate!==o?(p=0,n.removeClass(g).removeClass(f)):(p=t.reverse===!0?2:1,n.removeClass(d[p%2]).addClass(d[p-1]))},!0)}}}]),t.module("smart-table").directive("stPagination",function(){return{restrict:"EA",require:"^stTable",scope:{stItemsByPage:"=?",stDisplayedPages:"=?"},templateUrl:function(t,e){return e.stTemplate?e.stTemplate:"template/smart-table/pagination.html"},link:function(t,e,a,s){function n(){var e,a,n=s.tableState().pagination,r=1;for(t.currentPage=Math.floor(n.start/n.number)+1,r=Math.max(r,t.currentPage-Math.abs(Math.floor(t.stDisplayedPages/2))),e=r+t.stDisplayedPages,e>n.numberOfPages&&(e=n.numberOfPages+1,r=Math.max(1,e-t.stDisplayedPages)),t.pages=[],t.numPages=n.numberOfPages,a=r;e>a;a++)t.pages.push(a)}t.stItemsByPage=t.stItemsByPage?+t.stItemsByPage:10,t.stDisplayedPages=t.stDisplayedPages?+t.stDisplayedPages:5,t.currentPage=1,t.pages=[],t.$watch(function(){return s.tableState().pagination},n,!0),t.$watch("stItemsByPage",function(){t.selectPage(1)}),t.$watch("stDisplayedPages",n),t.selectPage=function(e){e>0&&e<=t.numPages&&s.slice((e-1)*t.stItemsByPage,t.stItemsByPage)},s.slice(0,t.stItemsByPage)}}}),t.module("smart-table").directive("stPipe",function(){return{require:"stTable",scope:{stPipe:"="},link:{pre:function(e,a,s,n){t.isFunction(e.stPipe)&&(n.preventPipeOnWatch(),n.pipe=function(){return e.stPipe(n.tableState(),n)})}}}})}(angular); \ No newline at end of file +!function(t,e){"use strict";t.module("smart-table",[]).run(["$templateCache",function(t){t.put("template/smart-table/pagination.html",'')}]),t.module("smart-table").controller("stTableController",["$scope","$parse","$filter","$attrs",function(a,s,n,r){function i(t){return t?[].concat(t):[]}function c(){m=i(l(a)),b===!0&&S.pipe()}var l,o,u=r.stTable,p=s(u),f=p.assign,g=n("orderBy"),d=n("filter"),m=i(p(a)),h={sort:{},search:{},pagination:{start:0}},b=!0,S=this;r.stSafeSrc&&(l=s(r.stSafeSrc),a.$watch(function(){var t=l(a);return t?t.length:0},function(t){t!==m.length&&c()}),a.$watch(function(){return l(a)},function(t,e){t!==e&&c()})),this.sortBy=function(e,a){return h.sort.predicate=e,h.sort.reverse=a===!0,t.isFunction(e)?h.sort.functionName=e.name:delete h.sort.functionName,h.pagination.start=0,this.pipe()},this.search=function(t,e){var a=h.search.predicateObject||{},s=e?e:"$";return a[s]=t,t||delete a[s],h.search.predicateObject=a,h.pagination.start=0,this.pipe()},this.pipe=function(){var t=h.pagination,s=h.search.predicateObject?d(m,h.search.predicateObject):m;h.sort.predicate&&(s=g(s,h.sort.predicate,h.sort.reverse)),t.number!==e&&(t.numberOfPages=s.length>0?Math.ceil(s.length/t.number):1,t.start=t.start>=s.length?(t.numberOfPages-1)*t.number:t.start,s=s.slice(t.start,t.start+parseInt(t.number))),f(a,s)},this.select=function(t,a){var s=m,n=s.indexOf(t);-1!==n&&("single"===a?(t.isSelected=t.isSelected!==!0,o&&(o.isSelected=!1),o=t.isSelected===!0?t:e):s[n].isSelected=!s[n].isSelected)},this.slice=function(t,e){return h.pagination.start=t,h.pagination.number=e,this.pipe()},this.tableState=function(){return h},this.setFilterFunction=function(t){d=n(t)},this.setSortFunction=function(t){g=n(t)},this.preventPipeOnWatch=function(){b=!1}}]).directive("stTable",function(){return{restrict:"A",controller:"stTableController",link:function(t,e,a,s){a.stSetFilter&&s.setFilterFunction(a.stSetFilter),a.stSetSort&&s.setSortFunction(a.stSetSort)}}}),t.module("smart-table").directive("stSearch",["$timeout",function(t){return{require:"^stTable",scope:{predicate:"=?stSearch"},link:function(e,a,s,n){var r=n,i=null,c=s.stDelay||400;e.$watch("predicate",function(t,e){t!==e&&(n.tableState().search={},r.search(a[0].value||"",t))}),e.$watch(function(){return n.tableState().search},function(t){var s=e.predicate||"$";t.predicateObject&&t.predicateObject[s]!==a[0].value&&(a[0].value=t.predicateObject[s]||"")},!0),a.bind("input",function(a){a=a.originalEvent||a,null!==i&&t.cancel(i),i=t(function(){r.search(a.target.value,e.predicate||""),i=null},c)})}}}]),t.module("smart-table").directive("stSelectRow",function(){return{restrict:"A",require:"^stTable",scope:{row:"=stSelectRow"},link:function(t,e,a,s){var n=a.stSelectMode||"single";e.bind("click",function(){t.$apply(function(){s.select(t.row,n)})}),t.$watch("row.isSelected",function(t){t===!0?e.addClass("st-selected"):e.removeClass("st-selected")})}}}),t.module("smart-table").directive("stSort",["$parse",function(a){return{restrict:"A",require:"^stTable",link:function(s,n,r,i){function c(){p++,o=t.isFunction(u(s))?u(s):r.stSort,p%3===0&&r.stSkipNatural===e?(p=0,i.tableState().sort={},i.tableState().pagination.start=0,i.pipe()):i.sortBy(o,p%2===0)}var l,o=r.stSort,u=a(o),p=0,f=r.stClassAscent||"st-sort-ascent",g=r.stClassDescent||"st-sort-descent",d=[f,g];r.stSortDefault&&(l=s.$eval(r.stSortDefault)!==e?s.$eval(r.stSortDefault):r.stSortDefault),n.bind("click",function(){o&&s.$apply(c)}),l&&(p="reverse"===r.stSortDefault?1:0,c()),s.$watch(function(){return i.tableState().sort},function(t){t.predicate!==o?(p=0,n.removeClass(f).removeClass(g)):(p=t.reverse===!0?2:1,n.removeClass(d[p%2]).addClass(d[p-1]))},!0)}}}]),t.module("smart-table").directive("stPagination",function(){return{restrict:"EA",require:"^stTable",scope:{stItemsByPage:"=?",stDisplayedPages:"=?"},templateUrl:function(t,e){return e.stTemplate?e.stTemplate:"template/smart-table/pagination.html"},link:function(t,e,a,s){function n(){var e,a,n=s.tableState().pagination,r=1;for(t.currentPage=Math.floor(n.start/n.number)+1,r=Math.max(r,t.currentPage-Math.abs(Math.floor(t.stDisplayedPages/2))),e=r+t.stDisplayedPages,e>n.numberOfPages&&(e=n.numberOfPages+1,r=Math.max(1,e-t.stDisplayedPages)),t.pages=[],t.numPages=n.numberOfPages,a=r;e>a;a++)t.pages.push(a)}t.stItemsByPage=t.stItemsByPage?+t.stItemsByPage:10,t.stDisplayedPages=t.stDisplayedPages?+t.stDisplayedPages:5,t.currentPage=1,t.pages=[],t.$watch(function(){return s.tableState().pagination},n,!0),t.$watch("stItemsByPage",function(){t.selectPage(1)}),t.$watch("stDisplayedPages",n),t.selectPage=function(e){e>0&&e<=t.numPages&&s.slice((e-1)*t.stItemsByPage,t.stItemsByPage)},s.slice(0,t.stItemsByPage)}}}),t.module("smart-table").directive("stPipe",function(){return{require:"stTable",scope:{stPipe:"="},link:{pre:function(e,a,s,n){t.isFunction(e.stPipe)&&(n.preventPipeOnWatch(),n.pipe=function(){return e.stPipe(n.tableState(),n)})}}}})}(angular); \ No newline at end of file diff --git a/package.json b/package.json index 5c86885a..5dfbd097 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "smart-table", - "version": "1.4.8", + "version": "1.4.9", "description": "", "main": "dist/smart-table.debug.js", "scripts": { diff --git a/src/stTable.js b/src/stTable.js index 0bf94df8..e40683be 100644 --- a/src/stTable.js +++ b/src/stTable.js @@ -1,179 +1,186 @@ ng.module('smart-table') - .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController($scope, $parse, $filter, $attrs) { - var propertyName = $attrs.stTable; - var displayGetter = $parse(propertyName); - var displaySetter = displayGetter.assign; - var safeGetter; - var orderBy = $filter('orderBy'); - var filter = $filter('filter'); - var safeCopy = copyRefs(displayGetter($scope)); - var tableState = { - sort: {}, - search: {}, - pagination: { - start: 0 - } - }; - var pipeAfterSafeCopy = true; - var ctrl = this; - var lastSelected; - - function copyRefs(src) { - return src ? [].concat(src) : []; + .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController($scope, $parse, $filter, $attrs) { + var propertyName = $attrs.stTable; + var displayGetter = $parse(propertyName); + var displaySetter = displayGetter.assign; + var safeGetter; + var orderBy = $filter('orderBy'); + var filter = $filter('filter'); + var safeCopy = copyRefs(displayGetter($scope)); + var tableState = { + sort: {}, + search: {}, + pagination: { + start: 0 + } + }; + var pipeAfterSafeCopy = true; + var ctrl = this; + var lastSelected; + + function copyRefs(src) { + return src ? [].concat(src) : []; + } + + function updateSafeCopy() { + safeCopy = copyRefs(safeGetter($scope)); + if (pipeAfterSafeCopy === true) { + ctrl.pipe(); + } + } + + if ($attrs.stSafeSrc) { + safeGetter = $parse($attrs.stSafeSrc); + $scope.$watch(function () { + var safeSrc = safeGetter($scope); + return safeSrc ? safeSrc.length : 0; + + }, function (newValue, oldValue) { + if (newValue !== safeCopy.length) { + updateSafeCopy(); } + }); + $scope.$watch(function () { + return safeGetter($scope); + }, function (newValue, oldValue) { + if (newValue !== oldValue) { + updateSafeCopy(); + } + }); + } + + /** + * sort the rows + * @param {Function | String} predicate - function or string which will be used as predicate for the sorting + * @param [reverse] - if you want to reverse the order + */ + this.sortBy = function sortBy(predicate, reverse) { + tableState.sort.predicate = predicate; + tableState.sort.reverse = reverse === true; + + if (ng.isFunction(predicate)) { + tableState.sort.functionName = predicate.name; + } else { + delete tableState.sort.functionName; + } + + tableState.pagination.start = 0; + return this.pipe(); + }; - function updateSafeCopy() { - safeCopy = copyRefs(safeGetter($scope)); - if (pipeAfterSafeCopy === true) { - ctrl.pipe(); - } + /** + * search matching rows + * @param {String} input - the input string + * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties + */ + this.search = function search(input, predicate) { + var predicateObject = tableState.search.predicateObject || {}; + var prop = predicate ? predicate : '$'; + predicateObject[prop] = input; + // to avoid to filter out null value + if (!input) { + delete predicateObject[prop]; + } + tableState.search.predicateObject = predicateObject; + tableState.pagination.start = 0; + return this.pipe(); + }; + + /** + * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect) + */ + this.pipe = function pipe() { + var pagination = tableState.pagination; + var filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy; + if (tableState.sort.predicate) { + filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse); + } + if (pagination.number !== undefined) { + pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1; + pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start; + filtered = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number)); + } + displaySetter($scope, filtered); + }; + + /** + * select a dataRow (it will add the attribute isSelected to the row object) + * @param {Object} row - the row to select + * @param {String} [mode] - "single" or "multiple" (multiple by default) + */ + this.select = function select(row, mode) { + var rows = safeCopy; + var index = rows.indexOf(row); + if (index !== -1) { + if (mode === 'single') { + row.isSelected = row.isSelected !== true; + if (lastSelected) { + lastSelected.isSelected = false; + } + lastSelected = row.isSelected === true ? row : undefined; + } else { + rows[index].isSelected = !rows[index].isSelected; } + } + }; + + /** + * take a slice of the current sorted/filtered collection (pagination) + * + * @param {Number} start - start index of the slice + * @param {Number} number - the number of item in the slice + */ + this.slice = function splice(start, number) { + tableState.pagination.start = start; + tableState.pagination.number = number; + return this.pipe(); + }; + + /** + * return the current state of the table + * @returns {{sort: {}, search: {}, pagination: {start: number}}} + */ + this.tableState = function getTableState() { + return tableState; + }; - if ($attrs.stSafeSrc) { - safeGetter = $parse($attrs.stSafeSrc); - $scope.$watch(function () { - var safeSrc = safeGetter($scope); - return safeSrc ? safeSrc.length : 0; - - }, function (newValue, oldValue) { - if (newValue !== safeCopy.length) { - updateSafeCopy(); - } - }); - $scope.$watch(function () { - return safeGetter($scope); - }, function (newValue, oldValue) { - if (newValue !== oldValue) { - updateSafeCopy(); - } - }); + /** + * Use a different filter function than the angular FilterFilter + * @param filterName the name under which the custom filter is registered + */ + this.setFilterFunction = function setFilterFunction(filterName) { + filter = $filter(filterName); + }; + + /** + *User a different function than the angular orderBy + * @param sortFunctionName the name under which the custom order function is registered + */ + this.setSortFunction = function setSortFunction(sortFunctionName) { + orderBy = $filter(sortFunctionName); + }; + + /** + * Usually when the safe copy is updated the pipe function is called. + * Calling this method will prevent it, which is something required when using a custom pipe function + */ + this.preventPipeOnWatch = function preventPipe() { + pipeAfterSafeCopy = false; + }; + }]) + .directive('stTable', function () { + return { + restrict: 'A', + controller: 'stTableController', + link: function (scope, element, attr, ctrl) { + + if (attr.stSetFilter) { + ctrl.setFilterFunction(attr.stSetFilter); } - /** - * sort the rows - * @param {Function | String} predicate - function or string which will be used as predicate for the sorting - * @param [reverse] - if you want to reverse the order - */ - this.sortBy = function sortBy(predicate, reverse) { - tableState.sort.predicate = predicate; - tableState.sort.reverse = reverse === true; - tableState.pagination.start = 0; - return this.pipe(); - }; - - /** - * search matching rows - * @param {String} input - the input string - * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties - */ - this.search = function search(input, predicate) { - var predicateObject = tableState.search.predicateObject || {}; - var prop = predicate ? predicate : '$'; - predicateObject[prop] = input; - // to avoid to filter out null value - if (!input) { - delete predicateObject[prop]; - } - tableState.search.predicateObject = predicateObject; - tableState.pagination.start = 0; - return this.pipe(); - }; - - /** - * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect) - */ - this.pipe = function pipe() { - var pagination = tableState.pagination; - var filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy; - if (tableState.sort.predicate) { - filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse); - } - if (pagination.number !== undefined) { - pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1; - pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start; - filtered = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number)); - } - displaySetter($scope, filtered); - }; - - /** - * select a dataRow (it will add the attribute isSelected to the row object) - * @param {Object} row - the row to select - * @param {String} [mode] - "single" or "multiple" (multiple by default) - */ - this.select = function select(row, mode) { - var rows = safeCopy; - var index = rows.indexOf(row); - if (index !== -1) { - if (mode === 'single') { - row.isSelected = row.isSelected !== true; - if (lastSelected) { - lastSelected.isSelected = false; - } - lastSelected = row.isSelected === true ? row : undefined; - } else { - rows[index].isSelected = !rows[index].isSelected; - } - } - }; - - /** - * take a slice of the current sorted/filtered collection (pagination) - * - * @param {Number} start - start index of the slice - * @param {Number} number - the number of item in the slice - */ - this.slice = function splice(start, number) { - tableState.pagination.start = start; - tableState.pagination.number = number; - return this.pipe(); - }; - - /** - * return the current state of the table - * @returns {{sort: {}, search: {}, pagination: {start: number}}} - */ - this.tableState = function getTableState() { - return tableState; - }; - - /** - * Use a different filter function than the angular FilterFilter - * @param filterName the name under which the custom filter is registered - */ - this.setFilterFunction = function setFilterFunction(filterName) { - filter = $filter(filterName); - }; - - /** - *User a different function than the angular orderBy - * @param sortFunctionName the name under which the custom order function is registered - */ - this.setSortFunction = function setSortFunction(sortFunctionName) { - orderBy = $filter(sortFunctionName); - }; - - /** - * Usually when the safe copy is updated the pipe function is called. - * Calling this method will prevent it, which is something required when using a custom pipe function - */ - this.preventPipeOnWatch = function preventPipe() { - pipeAfterSafeCopy = false; - }; - }]) - .directive('stTable', function () { - return { - restrict: 'A', - controller: 'stTableController', - link: function (scope, element, attr, ctrl) { - - if (attr.stSetFilter) { - ctrl.setFilterFunction(attr.stSetFilter); - } - - if (attr.stSetSort) { - ctrl.setSortFunction(attr.stSetSort); - } - } - }; - }); + if (attr.stSetSort) { + ctrl.setSortFunction(attr.stSetSort); + } + } + }; + }); diff --git a/test/spec/stSort.spec.js b/test/spec/stSort.spec.js index a88a0be4..1dbf75d2 100644 --- a/test/spec/stSort.spec.js +++ b/test/spec/stSort.spec.js @@ -44,7 +44,10 @@ describe('stSort Directive', function () { {name: 'Faivre', firstname: 'Blandine', age: 44} ]; scope.getters = { - age: function (row) { + age: function ageGetter(row) { + return row.name.length; + }, + name: function nameGetter(row) { return row.name.length; } }; @@ -54,6 +57,7 @@ describe('stSort Directive', function () { 'name' + 'firstname' + 'age' + + 'age' + '' + '' + '' + @@ -145,6 +149,19 @@ describe('stSort Directive', function () { }); + it('should switch from getter function to the other', function () { + var ths = element.find('th'); + var actual; + angular.element(ths[2]).triggerHandler('click'); + expect(hasClass(ths[2], 'st-sort-ascent')).toBe(true); + expect(hasClass(ths[3], 'st-sort-ascent')).toBe(false); + + angular.element(ths[3]).triggerHandler('click'); + expect(hasClass(ths[2], 'st-sort-ascent')).toBe(false); + expect(hasClass(ths[3], 'st-sort-ascent')).toBe(true); + + }); + it('should reset its class if table state has changed', function () { var ths = element.find('th'); angular.element(ths[1]).triggerHandler('click'); diff --git a/test/spec/stTable.spec.js b/test/spec/stTable.spec.js index c5a097b4..0cf4b48f 100644 --- a/test/spec/stTable.spec.js +++ b/test/spec/stTable.spec.js @@ -1,315 +1,351 @@ describe('st table Controller', function () { - var dataSet; - var scope; - var ctrl; - var childScope; - - beforeEach(module('smart-table')); - - describe('with a simple data-set', function() { - - beforeEach(inject(function ($rootScope, $controller, $filter, $parse) { - dataSet = [ - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Leponge', firstname: 'Bob', age: 22}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]; - scope = $rootScope; - childScope = scope.$new(); - scope.data = dataSet; - ctrl = $controller('stTableController', {$scope: scope, $parse: $parse, $filter: $filter, $attrs: { - stTable: 'data' - }}); - - })); - - describe('sort', function () { - it('should sort the data', function () { - ctrl.sortBy('firstname'); - expect(scope.data).toEqual([ - {name: 'Faivre', firstname: 'Blandine', age: 44}, - {name: 'Leponge', firstname: 'Bob', age: 22}, - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - }); - - it('should reverse the order if the flag is passed', function () { - ctrl.sortBy('firstname', true); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Leponge', firstname: 'Bob', age: 22}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - }); - - it('should support getter function predicate', function () { - ctrl.sortBy(function (row) { - return row.firstname.length; - }); - expect(scope.data).toEqual([ - {name: 'Leponge', firstname: 'Bob', age: 22}, - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - }); + var dataSet; + var scope; + var ctrl; + var childScope; + + beforeEach(module('smart-table')); + + describe('with a simple data-set', function () { + + beforeEach(inject(function ($rootScope, $controller, $filter, $parse) { + dataSet = [ + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Leponge', firstname: 'Bob', age: 22}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]; + scope = $rootScope; + childScope = scope.$new(); + scope.data = dataSet; + ctrl = $controller('stTableController', { + $scope: scope, $parse: $parse, $filter: $filter, $attrs: { + stTable: 'data' + } + }); + + })); + + describe('sort', function () { + it('should sort the data', function () { + ctrl.sortBy('firstname'); + expect(scope.data).toEqual([ + {name: 'Faivre', firstname: 'Blandine', age: 44}, + {name: 'Leponge', firstname: 'Bob', age: 22}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + }); + + it('should reverse the order if the flag is passed', function () { + ctrl.sortBy('firstname', true); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Leponge', firstname: 'Bob', age: 22}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + }); + + it('should support getter function predicate', function () { + ctrl.sortBy(function (row) { + return row.firstname.length; }); - - describe('search', function () { - it('should search based on property name ', function () { - ctrl.search('re', 'name'); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - }); - - it('should not filter out null value when input is empty string', inject(function ($controller, $parse, $filter) { - scope.data = [ - {name: null, firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]; - - //use another dataset for this particular spec - ctrl = $controller('stTableController', {$scope: scope, $parse: $parse, $filter: $filter, $attrs: { - stTable: 'data' - }}); - - - ctrl.search('re', 'name'); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - - ctrl.search('', 'name'); - - expect(scope.data).toEqual([ - {name: null, firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - - })); - - it('should search globally', function () { - ctrl.search('re'); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]) - }); - - it('should add different columns', function () { - ctrl.search('re', 'name'); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - - ctrl.search('re', 'firstname'); - - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Laurent', age: 66} - ]); - }); + expect(scope.data).toEqual([ + {name: 'Leponge', firstname: 'Bob', age: 22}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + }); + + it('should hold the function name when using a function as predicate', function () { + ctrl.sortBy(function firstNameLength(row) { + return row.firstname.length; }); - describe('slice', function () { - it('should slice the collection', function () { - ctrl.slice(1, 2); - expect(scope.data.length).toBe(2); - expect(scope.data).toEqual([ - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - }); - - it('limit to the last page if not enough data', function () { - ctrl.slice(7, 2); - expect(scope.data.length).toBe(1); - expect(scope.data).toEqual([ - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - }); + expect(scope.data).toEqual([ + {name: 'Leponge', firstname: 'Bob', age: 22}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + + expect(ctrl.tableState().sort.functionName).toBe('firstNameLength'); + + }); + + it('should reset the function name when sorting with something than function', function () { + ctrl.sortBy(function firstNameLength(row) { + return row.firstname.length; }); + expect(ctrl.tableState().sort.functionName).toBe('firstNameLength'); + ctrl.sortBy('name'); + expect(ctrl.tableState().sort.functionName).toBe(undefined); + expect(ctrl.tableState().sort.predicate).toBe('name'); + + }); - describe('pipe', function () { - it('should remembered the last slice length but start back to zero when sorting', function () { - ctrl.slice(1, 2); - expect(scope.data.length).toBe(2); - expect(scope.data).toEqual([ - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - - ctrl.sortBy('firstname'); - expect(scope.data.length).toBe(2); - expect(scope.data).toEqual([ - {name: 'Faivre', firstname: 'Blandine', age: 44}, - {name: 'Leponge', firstname: 'Bob', age: 22} - ]); - }); - - it('should remembered the last slice length but start back to zero when filtering', function () { - ctrl.slice(1, 2); - expect(scope.data.length).toBe(2); - expect(scope.data).toEqual([ - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - - ctrl.search('re', 'name'); - expect(scope.data.length).toBe(2); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - }); - - it('should remember sort state when filtering', function () { - ctrl.sortBy('firstname'); - expect(scope.data).toEqual([ - {name: 'Faivre', firstname: 'Blandine', age: 44}, - {name: 'Leponge', firstname: 'Bob', age: 22}, - {name: 'Francoise', firstname: 'Frere', age: 99}, - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - - ctrl.search('re', 'name'); - expect(scope.data).toEqual([ - {name: 'Faivre', firstname: 'Blandine', age: 44}, - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33} - ]); - - }); - - it('should remember filtering when sorting', function () { - ctrl.search('re', 'name'); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Laurent', age: 66}, - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44} - ]); - ctrl.sortBy('age'); - expect(scope.data).toEqual([ - {name: 'Renard', firstname: 'Olivier', age: 33}, - {name: 'Faivre', firstname: 'Blandine', age: 44}, - {name: 'Renard', firstname: 'Laurent', age: 66} - ]); - }); + + }); + + describe('search', function () { + it('should search based on property name ', function () { + ctrl.search('re', 'name'); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + }); + + it('should not filter out null value when input is empty string', inject(function ($controller, $parse, $filter) { + scope.data = [ + {name: null, firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]; + + //use another dataset for this particular spec + ctrl = $controller('stTableController', { + $scope: scope, $parse: $parse, $filter: $filter, $attrs: { + stTable: 'data' + } }); - describe('select', function () { - function getSelected(array) { - return array.filter(function (val) { - return val.isSelected === true; - }); - } + ctrl.search('re', 'name'); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + + ctrl.search('', 'name'); + + expect(scope.data).toEqual([ + {name: null, firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + + })); + + it('should search globally', function () { + ctrl.search('re'); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]) + }); + + it('should add different columns', function () { + ctrl.search('re', 'name'); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + + ctrl.search('re', 'firstname'); + + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Laurent', age: 66} + ]); + }); + }); + describe('slice', function () { + it('should slice the collection', function () { + ctrl.slice(1, 2); + expect(scope.data.length).toBe(2); + expect(scope.data).toEqual([ + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + }); + + it('limit to the last page if not enough data', function () { + ctrl.slice(7, 2); + expect(scope.data.length).toBe(1); + expect(scope.data).toEqual([ + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + }); + }); - it('should select only a single row at the time', function () { - ctrl.select(scope.data[3], 'single'); - var selected = getSelected(scope.data); - expect(selected.length).toBe(1); - expect(selected[0]).toEqual(scope.data[3]); + describe('pipe', function () { + it('should remembered the last slice length but start back to zero when sorting', function () { + ctrl.slice(1, 2); + expect(scope.data.length).toBe(2); + expect(scope.data).toEqual([ + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + + ctrl.sortBy('firstname'); + expect(scope.data.length).toBe(2); + expect(scope.data).toEqual([ + {name: 'Faivre', firstname: 'Blandine', age: 44}, + {name: 'Leponge', firstname: 'Bob', age: 22} + ]); + }); + + it('should remembered the last slice length but start back to zero when filtering', function () { + ctrl.slice(1, 2); + expect(scope.data.length).toBe(2); + expect(scope.data).toEqual([ + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + + ctrl.search('re', 'name'); + expect(scope.data.length).toBe(2); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + }); + + it('should remember sort state when filtering', function () { + ctrl.sortBy('firstname'); + expect(scope.data).toEqual([ + {name: 'Faivre', firstname: 'Blandine', age: 44}, + {name: 'Leponge', firstname: 'Bob', age: 22}, + {name: 'Francoise', firstname: 'Frere', age: 99}, + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + + ctrl.search('re', 'name'); + expect(scope.data).toEqual([ + {name: 'Faivre', firstname: 'Blandine', age: 44}, + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33} + ]); + + }); + + it('should remember filtering when sorting', function () { + ctrl.search('re', 'name'); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Laurent', age: 66}, + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44} + ]); + ctrl.sortBy('age'); + expect(scope.data).toEqual([ + {name: 'Renard', firstname: 'Olivier', age: 33}, + {name: 'Faivre', firstname: 'Blandine', age: 44}, + {name: 'Renard', firstname: 'Laurent', age: 66} + ]); + }); + }); - ctrl.select(scope.data[2], 'single'); + describe('select', function () { - selected = getSelected(scope.data); + function getSelected(array) { + return array.filter(function (val) { + return val.isSelected === true; + }); + } - expect(selected.length).toBe(1); - expect(selected[0]).toEqual(scope.data[2]); - }); - it('should select a row multiple times in single mode (#165)', function () { - ctrl.select(scope.data[3], 'single'); - var selected = getSelected(scope.data); - expect(selected.length).toBe(1); - expect(selected[0]).toEqual(scope.data[3]); + it('should select only a single row at the time', function () { + ctrl.select(scope.data[3], 'single'); + var selected = getSelected(scope.data); + expect(selected.length).toBe(1); + expect(selected[0]).toEqual(scope.data[3]); - ctrl.select(scope.data[3], 'single'); - selected = getSelected(scope.data); + ctrl.select(scope.data[2], 'single'); - expect(selected.length).toBe(0); + selected = getSelected(scope.data); - ctrl.select(scope.data[3], 'single'); - selected = getSelected(scope.data); + expect(selected.length).toBe(1); + expect(selected[0]).toEqual(scope.data[2]); + }); - expect(selected.length).toBe(1); - expect(selected[0]).toEqual(scope.data[3]); - }); + it('should select a row multiple times in single mode (#165)', function () { + ctrl.select(scope.data[3], 'single'); + var selected = getSelected(scope.data); + expect(selected.length).toBe(1); + expect(selected[0]).toEqual(scope.data[3]); - it('should select multiple row', function () { - ctrl.select(scope.data[3]); - ctrl.select(scope.data[4]); - var selected = getSelected(scope.data); - expect(selected.length).toBe(2); - expect(selected).toEqual([scope.data[3], scope.data[4]]); - }); + ctrl.select(scope.data[3], 'single'); + selected = getSelected(scope.data); - it('should unselect an item on mode single', function () { - ctrl.select(scope.data[3], 'single'); - var selected = getSelected(scope.data); - expect(selected.length).toBe(1); - expect(selected[0]).toEqual(scope.data[3]); + expect(selected.length).toBe(0); - ctrl.select(scope.data[3], 'single'); + ctrl.select(scope.data[3], 'single'); + selected = getSelected(scope.data); - selected = getSelected(scope.data); + expect(selected.length).toBe(1); + expect(selected[0]).toEqual(scope.data[3]); + }); - expect(selected.length).toBe(0); - }); + it('should select multiple row', function () { + ctrl.select(scope.data[3]); + ctrl.select(scope.data[4]); + var selected = getSelected(scope.data); + expect(selected.length).toBe(2); + expect(selected).toEqual([scope.data[3], scope.data[4]]); + }); - it('should unselect an item on mode multiple', function () { - ctrl.select(scope.data[3]); - ctrl.select(scope.data[4]); - var selected = getSelected(scope.data); - expect(selected.length).toBe(2); - expect(selected).toEqual([scope.data[3], scope.data[4]]); + it('should unselect an item on mode single', function () { + ctrl.select(scope.data[3], 'single'); + var selected = getSelected(scope.data); + expect(selected.length).toBe(1); + expect(selected[0]).toEqual(scope.data[3]); - ctrl.select(scope.data[3]); - selected = getSelected(scope.data); - expect(selected.length).toBe(1); - expect(selected).toEqual([scope.data[4]]); - }); - }); - }); + ctrl.select(scope.data[3], 'single'); - describe('with safeSrc', function () { - beforeEach(inject(function ($rootScope, $controller, $filter, $parse) { - dataSet = [ - {name: 'Renard', firstname: 'Laurent', age: 66} - ]; - scope = $rootScope; - scope.data = dataSet; - ctrl = $controller('stTableController', {$scope: scope, $parse: $parse, $filter: $filter, $attrs: { - stTable: 'tableData', - stSafeSrc: 'data' - }}); - })); - - it('adds tableData to the scope', function() { - scope.$digest() - expect(scope.tableData).toBeDefined() - expect(scope.tableData[0].name).toEqual('Renard'); - }); + selected = getSelected(scope.data); + + expect(selected.length).toBe(0); + }); + + it('should unselect an item on mode multiple', function () { + ctrl.select(scope.data[3]); + ctrl.select(scope.data[4]); + var selected = getSelected(scope.data); + expect(selected.length).toBe(2); + expect(selected).toEqual([scope.data[3], scope.data[4]]); + + ctrl.select(scope.data[3]); + selected = getSelected(scope.data); + expect(selected.length).toBe(1); + expect(selected).toEqual([scope.data[4]]); + }); + }); + }); + + describe('with safeSrc', function () { + beforeEach(inject(function ($rootScope, $controller, $filter, $parse) { + dataSet = [ + {name: 'Renard', firstname: 'Laurent', age: 66} + ]; + scope = $rootScope; + scope.data = dataSet; + ctrl = $controller('stTableController', { + $scope: scope, $parse: $parse, $filter: $filter, $attrs: { + stTable: 'tableData', + stSafeSrc: 'data' + } + }); + })); + + it('adds tableData to the scope', function () { + scope.$digest() + expect(scope.tableData).toBeDefined() + expect(scope.tableData[0].name).toEqual('Renard'); }); + }); });