UNPKG

zettapi_client

Version:

Client side CRUD operations in angular to use with zettapi_server rest api to get started quickly in any CMS project

1,246 lines (1,104 loc) 90.2 kB
(function(angular, factory) { 'use strict'; if (typeof define === 'function' && define.amd) { define(['angular'], function(angular) { return factory(angular); }); } else { return factory(angular); } }(window.angular || null, function(angular) { 'use strict'; /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function(){ /** * @ngdoc module * @name ngTable * @description ngTable: Table + Angular JS */ angular.module('ngTable', []); })(); /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function () { /** * @ngdoc object * @name ngTableDefaultParams * @module ngTable * @description Default Parameters for ngTable */ angular.module('ngTable') .value('ngTableDefaults', { params: {}, settings: {} }); })(); /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function(){ 'use strict'; angular.module('ngTable') .factory('ngTableEventsChannel', ngTableEventsChannel); ngTableEventsChannel.$inject = ['$rootScope']; /** * @ngdoc service * @name ngTableEventsChannel * @description strongly typed pub/sub for `NgTableParams` * * Supported events: * * * afterCreated - raised when a new instance of `NgTableParams` has finished being constructed * * afterReloadData - raised when the `reload` event has finished loading new data * * datasetChanged - raised when `settings` receives a new data array * * pagesChanged - raised when a new pages array has been generated */ function ngTableEventsChannel($rootScope){ var events = {}; events = addChangeEvent('afterCreated', events); events = addChangeEvent('afterReloadData', events); events = addChangeEvent('datasetChanged', events); events = addChangeEvent('pagesChanged', events); return events; ////////// function addChangeEvent(eventName, target){ var fnName = eventName.charAt(0).toUpperCase() + eventName.substring(1); var event = {}; event['on' + fnName] = createEventSubscriptionFn(eventName); event['publish' + fnName] = createPublishEventFn(eventName); return angular.extend(target, event); } function createEventSubscriptionFn(eventName){ return function subscription(handler/*[, eventSelector or $scope][, eventSelector]*/){ var eventSelector = angular.identity; var scope = $rootScope; if (arguments.length === 2){ if (angular.isFunction(arguments[1].$new)) { scope = arguments[1]; } else { eventSelector = arguments[1] } } else if (arguments.length > 2){ scope = arguments[1]; eventSelector = arguments[2]; } // shorthand for subscriber to only receive events from a specific publisher instance if (angular.isObject(eventSelector)) { var requiredPublisher = eventSelector; eventSelector = function(publisher){ return publisher === requiredPublisher; } } return scope.$on('ngTable:' + eventName, function(event, params/*, ...args*/){ // don't send events published by the internal NgTableParams created by ngTableController if (params.isNullInstance) return; var eventArgs = rest(arguments, 2); var fnArgs = [params].concat(eventArgs); if (eventSelector.apply(this, fnArgs)){ handler.apply(this, fnArgs); } }); } } function createPublishEventFn(eventName){ return function publish(/*args*/){ var fnArgs = ['ngTable:' + eventName].concat(Array.prototype.slice.call(arguments)); $rootScope.$broadcast.apply($rootScope, fnArgs); } } function rest(array, n) { return Array.prototype.slice.call(array, n == null ? 1 : n); } } })(); /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function(){ 'use strict'; angular.module('ngTable') .provider('ngTableFilterConfig', ngTableFilterConfigProvider); ngTableFilterConfigProvider.$inject = []; function ngTableFilterConfigProvider(){ var config; var defaultConfig = { defaultBaseUrl: 'ng-table/filters/', defaultExt: '.html', aliasUrls: {} }; this.$get = ngTableFilterConfig; this.resetConfigs = resetConfigs; this.setConfig = setConfig; init(); ///////// function init(){ resetConfigs(); } function resetConfigs(){ config = defaultConfig; } function setConfig(customConfig){ var mergeConfig = angular.extend({}, config, customConfig); mergeConfig.aliasUrls = angular.extend({}, config.aliasUrls, customConfig.aliasUrls); config = mergeConfig; } ///////// ngTableFilterConfig.$inject = []; function ngTableFilterConfig(){ var publicConfig; var service = { config: publicConfig, getTemplateUrl: getTemplateUrl, getUrlForAlias: getUrlForAlias }; Object.defineProperty(service, "config", { get: function(){ return publicConfig = publicConfig || angular.copy(config); }, enumerable: true }); return service; ///////// function getTemplateUrl(filterDef, filterKey){ if (angular.isObject(filterDef)){ filterDef = filterDef.id; } if (filterDef.indexOf('/') !== -1){ return filterDef; } return service.getUrlForAlias(filterDef, filterKey); } function getUrlForAlias(aliasName/*, filterKey*/){ return config.aliasUrls[aliasName] || config.defaultBaseUrl + aliasName + config.defaultExt; } } } })(); /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function(){ 'use strict'; angular.module('ngTable') .provider('ngTableDefaultGetData', ngTableDefaultGetDataProvider); ngTableDefaultGetDataProvider.$inject = []; /** * @ngdoc provider * @name ngTableDefaultGetDataProvider * @description Allows for the configuration of the ngTableDefaultGetData service. * * Set filterFilterName to the name of a angular filter that knows how to apply the values returned by * `NgTableParams.filter()` to restrict an array of data. * * Set sortingFilterName to the name of a angular filter that knows how to apply the values returned by * `NgTableParams.orderBy()` to sort an array of data. * * Out of the box the `ngTableDefaultGetData` service will be configured to use the angular `filter` and `orderBy` * filters respectively */ function ngTableDefaultGetDataProvider(){ var provider = this; provider.$get = ngTableDefaultGetData; provider.filterFilterName = 'filter'; provider.sortingFilterName = 'orderBy'; /////////// ngTableDefaultGetData.$inject = ['$filter']; /** * @ngdoc service * @name ngTableDefaultGetData * @description A default implementation of the getData function that will apply the `filter`, `orderBy` and * paging values from the `NgTableParams` instance supplied to the data array supplied. * * The outcome will be to return the resulting array and to assign the total item count after filtering * to the `total` of the `NgTableParams` instance supplied */ function ngTableDefaultGetData($filter) { var defaultDataOptions = {applyFilter: true, applySort: true, applyPaging: true}; getData.applyPaging = applyPaging; getData.getFilterFn = getFilterFn; getData.getOrderByFn = getOrderByFn; return getData; function getFilterFn(params) { var filterOptions = params.settings().filterOptions; if (angular.isFunction(filterOptions.filterFn)){ return filterOptions.filterFn; } else { return $filter(filterOptions.filterFilterName || provider.filterFilterName); } } function getOrderByFn (/*params*/){ return $filter(provider.sortingFilterName); } function applyFilter(data, params) { if (!params.hasFilter()) { return data; } var filter = params.filter(true); var filterKeys = Object.keys(filter); var parsedFilter = filterKeys.reduce(function(result, key){ result = setPath(result, filter[key], key); return result; }, {}); var filterFn = getFilterFn(params); return filterFn.call(params, data, parsedFilter, params.settings().filterOptions.filterComparator); } function applyPaging(data, params) { var pagedData = data.slice((params.page() - 1) * params.count(), params.page() * params.count()); params.total(data.length); // set total for recalc pagination return pagedData; } function applySort(data, params) { var orderBy = params.orderBy(); var orderByFn = getOrderByFn(params); return orderBy.length ? orderByFn(data, orderBy) : data; } function getData(data, params) { if (data == null){ return []; } var options = angular.extend({}, defaultDataOptions, params.settings().dataOptions); var fData = options.applyFilter ? applyFilter(data, params) : data; var orderedData = options.applySort ? applySort(fData, params) : fData; return options.applyPaging ? applyPaging(orderedData, params) : orderedData; } // Sets the value at any depth in a nested object based on the path // note: adapted from: underscore-contrib#setPath function setPath(obj, value, path) { var keys = path.split('.'); var ret = obj; var lastKey = keys[keys.length -1]; var target = ret; var parentPathKeys = keys.slice(0, keys.length -1); parentPathKeys.forEach(function(key) { if (!target.hasOwnProperty(key)) { target[key] = {}; } target = target[key]; }); target[lastKey] = value; return ret; } } } })(); /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function () { /** * @ngdoc service * @name ngTableColumn * @module ngTable * @description * Service to construct a $column definition used by {@link ngTable ngTable} directive */ angular.module('ngTable').factory('ngTableColumn', [function () { return { buildColumn: buildColumn }; ////////////// /** * @ngdoc method * @name ngTableColumn#buildColumn * @description Creates a $column for use within a header template * * @param {Object} column an existing $column or simple column data object * @param {Scope} defaultScope the $scope to supply to the $column getter methods when not supplied by caller * @param {Array} columns a reference to the columns array to make available on the context supplied to the * $column getter methods * @returns {Object} a $column object */ function buildColumn(column, defaultScope, columns){ // note: we're not modifying the original column object. This helps to avoid unintended side affects var extendedCol = Object.create(column); var defaults = createDefaults(); for (var prop in defaults) { if (extendedCol[prop] === undefined) { extendedCol[prop] = defaults[prop]; } if(!angular.isFunction(extendedCol[prop])){ // wrap raw field values with "getter" functions // - this is to ensure consistency with how ngTable.compile builds columns // - note that the original column object is being "proxied"; this is important // as it ensure that any changes to the original object will be returned by the "getter" (function(prop1){ var getterSetter = function getterSetter(/*[value] || [$scope, locals]*/) { if (arguments.length === 1 && !isScopeLike(arguments[0])) { getterSetter.assign(null, arguments[0]); } else { return column[prop1]; } }; getterSetter.assign = function($scope, value){ column[prop1] = value; }; extendedCol[prop1] = getterSetter; })(prop); } (function(prop1){ // satisfy the arguments expected by the function returned by parsedAttribute in the ngTable directive var getterFn = extendedCol[prop1]; extendedCol[prop1] = function () { if (arguments.length === 1 && !isScopeLike(arguments[0])){ getterFn.assign(null, arguments[0]); } else { var scope = arguments[0] || defaultScope; var context = Object.create(scope); angular.extend(context, { $column: extendedCol, $columns: columns }); return getterFn.call(column, context); } }; if (getterFn.assign){ extendedCol[prop1].assign = getterFn.assign; } })(prop); } return extendedCol; } function createDefaults(){ return { 'class': createGetterSetter(''), filter: createGetterSetter(false), groupable: createGetterSetter(false), filterData: angular.noop, headerTemplateURL: createGetterSetter(false), headerTitle: createGetterSetter(''), sortable: createGetterSetter(false), show: createGetterSetter(true), title: createGetterSetter(''), titleAlt: createGetterSetter('') }; } function createGetterSetter(initialValue){ var value = initialValue; var getterSetter = function getterSetter(/*[value] || [$scope, locals]*/){ if (arguments.length === 1 && !isScopeLike(arguments[0])) { getterSetter.assign(null, arguments[0]); } else { return value; } }; getterSetter.assign = function($scope, newValue){ value = newValue; }; return getterSetter; } function isScopeLike(object){ return object != null && angular.isFunction(object.$new); } }]); })(); /** * ngTable: Table + Angular JS * * @author Vitalii Savchuk <esvit666@gmail.com> * @url https://github.com/esvit/ng-table/ * @license New BSD License <http://creativecommons.org/licenses/BSD/> */ (function(){ /** * @ngdoc service * @name NgTableParams * @module ngTable * @description Parameters manager for ngTable */ angular.module('ngTable').factory('NgTableParams', ['$q', '$log', '$filter', 'ngTableDefaults', 'ngTableDefaultGetData', 'ngTableEventsChannel', function($q, $log, $filter, ngTableDefaults, ngTableDefaultGetData, ngTableEventsChannel) { var isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n); }; var NgTableParams = function(baseParameters, baseSettings) { // the ngTableController "needs" to create a dummy/null instance and it's important to know whether an instance // is one of these if (typeof baseParameters === "boolean"){ this.isNullInstance = true; } var self = this, prevParamsMemento, errParamsMemento, isCommittedDataset = false, initialEvents = [], log = function() { if (settings.debugMode && $log.debug) { $log.debug.apply($log, arguments); } }, defaultFilterOptions = { filterComparator: undefined, // look for a substring match in case insensitive way filterDelay: 500, filterDelayThreshold: 10000, // size of dataset array that will trigger the filterDelay being applied filterFilterName: undefined, // when defined overrides ngTableDefaultGetDataProvider.filterFilterName filterFn: undefined, // when defined overrides the filter function that ngTableDefaultGetData uses filterLayout: 'stack' // alternative: 'horizontal' }, defaultGroupOptions = { defaultSort: 'asc', // set to 'asc' or 'desc' to apply sorting to groups isExpanded: true }, defaultSettingsFns = getDefaultSettingFns(); this.data = []; /** * @ngdoc method * @name NgTableParams#parameters * @description Set new parameters or get current parameters * * @param {string} newParameters New parameters * @param {string} parseParamsFromUrl Flag if parse parameters like in url * @returns {Object} Current parameters or `this` */ this.parameters = function(newParameters, parseParamsFromUrl) { parseParamsFromUrl = parseParamsFromUrl || false; if (angular.isDefined(newParameters)) { for (var key in newParameters) { var value = newParameters[key]; if (parseParamsFromUrl && key.indexOf('[') >= 0) { var keys = key.split(/\[(.*)\]/).reverse() var lastKey = ''; for (var i = 0, len = keys.length; i < len; i++) { var name = keys[i]; if (name !== '') { var v = value; value = {}; value[lastKey = name] = (isNumber(v) ? parseFloat(v) : v); } } if (lastKey === 'sorting') { params[lastKey] = {}; } params[lastKey] = angular.extend(params[lastKey] || {}, value[lastKey]); } else { if (key === 'group'){ params[key] = parseGroup(newParameters[key]); } else { params[key] = (isNumber(newParameters[key]) ? parseFloat(newParameters[key]) : newParameters[key]); } } } log('ngTable: set parameters', params); return this; } return params; }; function parseGroup(group){ var defaultSort = settings.groupOptions && settings.groupOptions.defaultSort; if (angular.isFunction(group)) { if (group.sortDirection == null){ group.sortDirection = defaultSort; } return group; } else if (angular.isString(group)) { var grp = {}; grp[group] = defaultSort; return grp; } else if (angular.isObject(group)) { for (var key in group) { if (group[key] == null){ group[key] = defaultSort; } } return group; } else { return group; } } /** * @ngdoc method * @name NgTableParams#settings * @description Set new settings for table * * @param {string} newSettings New settings or undefined * @returns {Object} Current settings or `this` */ this.settings = function(newSettings) { if (angular.isDefined(newSettings)) { // todo: don't modify newSettings object: this introduces unexpected side effects; // instead take a copy of newSettings if (newSettings.filterOptions){ newSettings.filterOptions = angular.extend({}, settings.filterOptions, newSettings.filterOptions); } if (newSettings.groupOptions){ newSettings.groupOptions = angular.extend({}, settings.groupOptions, newSettings.groupOptions); } if (angular.isArray(newSettings.dataset)) { //auto-set the total from passed in dataset newSettings.total = newSettings.dataset.length; } var originalDataset = settings.dataset; settings = angular.extend(settings, newSettings); if (angular.isArray(newSettings.dataset)) { optimizeFilterDelay(); } // note: using != as want null and undefined to be treated the same var hasDatasetChanged = newSettings.hasOwnProperty('dataset') && (newSettings.dataset != originalDataset); if (hasDatasetChanged) { if (isCommittedDataset){ this.page(1); // reset page as a new dataset has been supplied } isCommittedDataset = false; var fireEvent = function () { ngTableEventsChannel.publishDatasetChanged(self, newSettings.dataset, originalDataset); }; if (initialEvents){ initialEvents.push(fireEvent); } else { fireEvent(); } } log('ngTable: set settings', settings); return this; } return settings; }; /** * @ngdoc method * @name NgTableParams#page * @description If parameter page not set return current page else set current page * * @param {string} page Page number * @returns {Object|Number} Current page or `this` */ this.page = function(page) { return angular.isDefined(page) ? this.parameters({ 'page': page }) : params.page; }; /** * @ngdoc method * @name NgTableParams#total * @description If parameter total not set return current quantity else set quantity * * @param {string} total Total quantity of items * @returns {Object|Number} Current page or `this` */ this.total = function(total) { return angular.isDefined(total) ? this.settings({ 'total': total }) : settings.total; }; /** * @ngdoc method * @name NgTableParams#count * @description If parameter count not set return current count per page else set count per page * * @param {string} count Count per number * @returns {Object|Number} Count per page or `this` */ this.count = function(count) { // reset to first page because can be blank page return angular.isDefined(count) ? this.parameters({ 'count': count, 'page': 1 }) : params.count; }; /** * @ngdoc method * @name NgTableParams#filter * @description If 'filter' parameter not set return current filter else set current filter * * Note: when assigning a new filter, {@link NgTableParams#page page} will be set to 1 * * @param {Object|Boolean} filter 'object': new filter to assign or * 'true': to return the current filter minus any insignificant values (null, undefined and empty string); or * 'falsey': to return the current filter "as is" * @returns {Object} Current filter or `this` */ this.filter = function(filter) { if (angular.isDefined(filter) && angular.isObject(filter)) { return this.parameters({ 'filter': filter, 'page': 1 }); } else if (filter === true){ var keys = Object.keys(params.filter); var significantFilter = {}; for (var i=0; i < keys.length; i++){ var filterValue = params.filter[keys[i]]; if (filterValue != null && filterValue !== '') { significantFilter[keys[i]] = filterValue; } } return significantFilter; } else { return params.filter; } }; /** * @ngdoc method * @name NgTableParams#group * @description If 'group' parameter is not set, return current grouping. Otherwise set current group. * * @param {string|Function|Object} group New group field * @param {string} sortDirection Optional direction that the list of groups should be sorted * @returns {Object} Current grouping or `this` */ this.group = function(group, sortDirection) { if (!angular.isDefined(group)){ return params.group; } var newParameters = { page: 1 }; if (angular.isFunction(group) && angular.isDefined(sortDirection)){ group.sortDirection = sortDirection; newParameters.group = group; } else if (angular.isDefined(group) && angular.isDefined(sortDirection)) { var groupArray = {}; groupArray[group] = sortDirection; newParameters.group = groupArray; } else { newParameters.group = group; } this.parameters(newParameters); return this; }; /** * @ngdoc method * @name NgTableParams#sorting * @description If 'sorting' parameter is not set, return current sorting. Otherwise set current sorting. * * @param {string} sorting New sorting * @returns {Object} Current sorting or `this` */ this.sorting = function(sorting) { if (arguments.length == 2) { var sortArray = {}; sortArray[sorting] = arguments[1]; this.parameters({ 'sorting': sortArray }); return this; } return angular.isDefined(sorting) ? this.parameters({ 'sorting': sorting }) : params.sorting; }; /** * @ngdoc method * @name NgTableParams#isSortBy * @description Checks sort field * * @param {string} field Field name * @param {string} direction Optional direction of sorting ('asc' or 'desc') * @returns {Array} Return true if field sorted by direction */ this.isSortBy = function(field, direction) { if(direction !== undefined) { return angular.isDefined(params.sorting[field]) && params.sorting[field] == direction; } else { return angular.isDefined(params.sorting[field]); } }; /** * @ngdoc method * @name NgTableParams#orderBy * @description Return object of sorting parameters for angular filter * * @returns {Array} Array like: [ '-name', '+age' ] */ this.orderBy = function() { return convertSortToOrderBy(params.sorting); }; function convertSortToOrderBy(sorting){ var result = []; for (var column in sorting) { result.push((sorting[column] === "asc" ? "+" : "-") + column); } return result; } /** * @ngdoc method * @name NgTableParams#generatePagesArray * @description Generate array of pages * * When no arguments supplied, the current parameter state of this `NgTableParams` instance will be used * * @param {boolean} currentPage which page must be active * @param {boolean} totalItems Total quantity of items * @param {boolean} pageSize Quantity of items on page * @param {number} maxBlocks Quantity of blocks for pagination * @returns {Array} Array of pages */ this.generatePagesArray = function(currentPage, totalItems, pageSize, maxBlocks) { if (!arguments.length){ currentPage = this.page(); totalItems = this.total(); pageSize = this.count(); } var maxPage, maxPivotPages, minPage, numPages, pages; maxBlocks = maxBlocks && maxBlocks < 6 ? 6 : maxBlocks; pages = []; numPages = Math.ceil(totalItems / pageSize); if (numPages > 1) { pages.push({ type: 'prev', number: Math.max(1, currentPage - 1), active: currentPage > 1 }); pages.push({ type: 'first', number: 1, active: currentPage > 1, current: currentPage === 1 }); maxPivotPages = Math.round((settings.paginationMaxBlocks - settings.paginationMinBlocks) / 2); minPage = Math.max(2, currentPage - maxPivotPages); maxPage = Math.min(numPages - 1, currentPage + maxPivotPages * 2 - (currentPage - minPage)); minPage = Math.max(2, minPage - (maxPivotPages * 2 - (maxPage - minPage))); var i = minPage; while (i <= maxPage) { if ((i === minPage && i !== 2) || (i === maxPage && i !== numPages - 1)) { pages.push({ type: 'more', active: false }); } else { pages.push({ type: 'page', number: i, active: currentPage !== i, current: currentPage === i }); } i++; } pages.push({ type: 'last', number: numPages, active: currentPage !== numPages, current: currentPage === numPages }); pages.push({ type: 'next', number: Math.min(numPages, currentPage + 1), active: currentPage < numPages }); } return pages; }; /** * @ngdoc method * @name NgTableParams#isDataReloadRequired * @description Return true when a change to this `NgTableParams` instance should require the reload method * to be run so as to ensure the data presented to the user reflects the `NgTableParams` * * Note that this method will return false when the reload method has run but fails. In this case * `hasErrorState` will return true. */ this.isDataReloadRequired = function(){ // note: using != as want to treat null and undefined the same return !isCommittedDataset || !angular.equals(createComparableParams(), prevParamsMemento) || hasGlobalSearchFieldChanges(); }; function createComparableParams(){ var result = {params: params}; if (angular.isFunction(params.group)){ result.groupSortDirection = params.group.sortDirection; } return result } /** * @ngdoc method * @name NgTableParams#hasFilter * @description Determines if NgTableParams#filter has significant filter value(s) * (any value except null, undefined, or empty string) * @returns {Boolean} true when NgTableParams#filter has at least one significant field value */ this.hasFilter = function(){ return Object.keys(this.filter(true)).length > 0; }; /** * @ngdoc method * @name NgTableParams#hasGroup * @description Determines if at least one group has been set * @returns {Boolean} */ this.hasGroup = function(group, sortDirection){ if (group == null) { return angular.isFunction(params.group) || Object.keys(params.group).length > 0 } if (angular.isFunction(group)) { if (sortDirection == null) { return params.group === group; } else { return params.group === group && group.sortDirection === sortDirection; } } else { if (sortDirection == null) { return Object.keys(params.group).indexOf(group) !== -1; } else { return params.group[group] === sortDirection; } } }; /** * @ngdoc method * @name NgTableParams#hasFilterChanges * @description Return true when a change to `NgTableParams.filters`require the reload method * to be run so as to ensure the data presented to the user reflects these filters */ this.hasFilterChanges = function(){ var previousFilter = (prevParamsMemento && prevParamsMemento.params.filter); return !angular.equals((params.filter), previousFilter) || hasGlobalSearchFieldChanges(); }; function hasGlobalSearchFieldChanges(){ var currentVal = (params.filter && params.filter.$); var previousVal = (prevParamsMemento && prevParamsMemento.params.filter && prevParamsMemento.params.filter.$); return !angular.equals(currentVal, previousVal); } /** * @ngdoc method * @name NgTableParams#url * @description Return groups for table grouping * * @param {boolean} asString flag indicates return array of string or object * @returns {Array} If asString = true will be return array of url string parameters else key-value object */ this.url = function(asString) { asString = asString || false; var pairs = (asString ? [] : {}); for (var key in params) { if (params.hasOwnProperty(key)) { var item = params[key], name = encodeURIComponent(key); if (typeof item === "object") { for (var subkey in item) { if (isSignificantValue(item[subkey], key)) { var pname = name + "[" + encodeURIComponent(subkey) + "]"; collectValue(item[subkey], pname); } } } else if (!angular.isFunction(item) && isSignificantValue(item, key)) { collectValue(item, name); } } } return pairs; function collectValue(value, key){ if (asString) { pairs.push(key + "=" + encodeURIComponent(value)); } else { pairs[key] = encodeURIComponent(value); } } function isSignificantValue(value, key){ return key === "group" ? true : angular.isDefined(value) && value !== ""; } }; /** * @ngdoc method * @name NgTableParams#reload * @description Reload table data */ this.reload = function() { var self = this, pData = null; settings.$loading = true; prevParamsMemento = angular.copy(createComparableParams()); isCommittedDataset = true; if (self.hasGroup()) { pData = runInterceptorPipeline($q.when(settings.getGroups(self))); } else { pData = runInterceptorPipeline($q.when(settings.getData(self))); } log('ngTable: reload data'); var oldData = self.data; return pData.then(function(data) { settings.$loading = false; errParamsMemento = null; self.data = data; // note: I think it makes sense to publish this event even when data === oldData // subscribers can always set a filter to only receive the event when data !== oldData ngTableEventsChannel.publishAfterReloadData(self, data, oldData); self.reloadPages(); return data; }).catch(function(reason){ errParamsMemento = prevParamsMemento; // "rethrow" return $q.reject(reason); }); }; /** * @ngdoc method * @name NgTableParams#hasErrorState * @description Return true when an attempt to `reload` the current `parameter` values have resulted in * a failure * * This method will continue to return true until the reload is successfully called or when the * `parameter` values have changed */ this.hasErrorState = function(){ return !!(errParamsMemento && angular.equals(errParamsMemento, createComparableParams())); }; function optimizeFilterDelay(){ // don't debounce by default filter input when working with small synchronous datasets if (settings.filterOptions.filterDelay === defaultFilterOptions.filterDelay && settings.total <= settings.filterOptions.filterDelayThreshold && settings.getData === defaultSettingsFns.getData){ settings.filterOptions.filterDelay = 0; } } this.reloadPages = (function() { var currentPages; return function(){ var oldPages = currentPages; var newPages = self.generatePagesArray(self.page(), self.total(), self.count()); if (!angular.equals(oldPages, newPages)){ currentPages = newPages; ngTableEventsChannel.publishPagesChanged(this, newPages, oldPages); } } })(); function runInterceptorPipeline(fetchedData){ var interceptors = settings.interceptors || []; return interceptors.reduce(function(result, interceptor){ var thenFn = (interceptor.response && interceptor.response.bind(interceptor)) || $q.when; var rejectFn = (interceptor.responseError && interceptor.responseError.bind(interceptor)) || $q.reject; return result.then(function(data){ return thenFn(data, self); }, function(reason){ return rejectFn(reason, self); }); }, fetchedData); } function getDefaultSettingFns(){ return { getData: getData, getGroups: getGroups }; /** * @ngdoc method * @name settings#getData * @description Returns the data to display in the table * * Called by `NgTableParams` whenever it considers new data is to be loaded * * @param {Object} params the `NgTableParams` requesting data */ function getData(params) { return ngTableDefaultGetData(params.settings().dataset, params); } /** * @ngdoc method * @name settings#getGroups * @description Return groups of data to display in the table * * Called by `NgTableParams` whenever it considers new data is to be loaded * and when a `group` value has been assigned * * @param {Object} params the `NgTableParams` requesting data */ function getGroups(params) { var group = params.group(); var groupFn; var sortDirection = undefined; if (angular.isFunction(group)) { groupFn = group; sortDirection = group.sortDirection; } else { // currently support for only one group implemented var groupField = Object.keys(group)[0]; sortDirection = group[groupField]; groupFn = function(item){ return getPath(item, groupField); }; } var settings = params.settings(); var originalDataOptions = settings.dataOptions; settings.dataOptions = { applyPaging: false }; var gotData = $q.when(settings.getData(params)); return gotData.then(function(data) { var groups = {}; angular.forEach(data, function(item) { var groupName = groupFn(item); groups[groupName] = groups[groupName] || { data: [], $hideRows: !settings.groupOptions.isExpanded, value: groupName }; groups[groupName].data.push(item); }); var result = []; for (var i in groups) { result.push(groups[i]); } if (sortDirection) { var orderByFn = ngTableDefaultGetData.getOrderByFn(); var orderBy = convertSortToOrderBy({ value: sortDirection }); result = orderByFn(result, orderBy); } return ngTableDefaultGetData.applyPaging(result, params); }).finally(function(){ // restore the real options settings.dataOptions = originalDataOptions; }); } function getPath (obj, ks) { // origianl source https://github.com/documentcloud/underscore-contrib if (typeof ks == "string") ks = ks.split("."); // If we have reached an undefined property // then stop executing and return undefined if (obj === undefined) return void 0; // If the path array has no more elements, we've reached // the intended property and return its value if (ks.length === 0) return obj; // If we still have elements in the path array and the current // value is null, stop executing and return undefined if (obj === null) return void 0; return getPath(obj[ks[0]], ks.slice(1)); } } var params = { page: 1, count: 10, filter: {}, sorting: {}, group: {} }; angular.extend(params, ngTableDefaults.params); /** * @ngdoc object * @name settings * @module ngTable * @description configuration settings for `NgTableParams` */ var settings = { $loading: false, dataset: null, //allows data to be set when table is initialized total: 0, defaultSort: 'desc', filterOptions: angular.copy(defaultFilterOptions), groupOptions: angular.copy(defaultGroupOptions), counts: [10, 25, 50, 100], interceptors: [],