import ngModule from '../../module'; import ModelProxy from '../model-proxy/model-proxy'; import {mergeWhere, mergeFilters} from 'vn-loopback/common/filter.js'; export default class CrudModel extends ModelProxy { constructor($q, $http) { super(); this.$http = $http; this.$q = $q; this.primaryKey = 'id'; this.autoLoad = true; } $onInit() { this.autoRefresh(); } /** * Whether the model is loading. */ get isLoading() { return this.canceler != null; } set url(url) { if (this._url === url) return; this._url = url; this.clear(); this.autoRefresh(); } get url() { return this._url; } autoRefresh() { if (this.autoLoad) return this.refresh(); return this.$q.resolve(); } buildFilter() { let order = this.order; if (typeof order === 'string') order = this.order.split(/\s*,\s*/); let myFilter = { fields: this.fields, where: mergeWhere(this.link, this.where), include: this.include, order: order, limit: this.limit }; let filter = this.filter; filter = mergeFilters(myFilter, filter); filter = mergeFilters(this.userFilter, filter); return filter; } /** * Refresh the model data. * * @return {Promise} The request promise */ refresh() { if (!this._url) return this.$q.resolve(); return this.sendRequest(this.buildFilter()); } /** * Applies a new filter to the model. * * @param {Object} userFilter The Loopback filter * @param {Object} userParams Custom parameters * @return {Promise} The request promise */ applyFilter(userFilter, userParams) { this.userFilter = userFilter; this.userParams = userParams; return this.refresh(); } /** * Adds a filter to the model. * * @param {Object} userFilter The Loopback filter * @param {Object} userParams Custom parameters * @return {Promise} The request promise */ addFilter(userFilter, userParams) { this.userFilter = mergeFilters(userFilter, this.userFilter); Object.assign(this.userParams, userParams); return this.refresh(); } /** * Removes the currently applied user filters. * * @return {Promise} The request promise */ removeFilter() { return applyFilter(null, null); } /** * Cancels the current request, if any. */ cancelRequest() { if (this.canceler) { this.canceler.resolve(); this.canceler = null; } } /** * When limit is enabled, loads the next set of rows. * * @return {Promise} The request promise */ loadMore() { if (!this.moreRows) return this.$q.resolve(); let filter = Object.assign({}, this.currentFilter); filter.skip = this.orgData ? this.orgData.length : 0; return this.sendRequest(filter, true); } /** * Clears the model, removing all it's data. */ clear() { this.orgData = null; } /** * Returns an object with the unsaved changes made to the model. * * @return {Object} The current changes */ getChanges() { if (!this.isChanged) return null; let create = []; let update = []; let remove = []; let pk = this.primaryKey; for (let row of this.removed) remove.push(row.$orgRow[pk]); for (let row of this._data) { if (row.$isNew) { let data = {}; for (let prop in row) if (prop.charAt(0) !== '$') data[prop] = row[prop]; create.push(data); } else if (row.$oldData) { let data = {}; for (let prop in row.$oldData) data[prop] = row[prop]; update.push({ data, where: {[pk]: row.$orgRow[pk]} }); } } let changes = { create: create, update: update, delete: remove }; return changes; } /** * Saves current changes on the server. * * @return {Promise} The save request promise */ save() { let changes = this.getChanges(); if (!changes) return this.$q.resolve(); let url = this.saveUrl ? this.saveUrl : `${this._url}/crud`; return this.$http.post(url, changes) .then(() => this.applyChanges()); } buildParams() { let params = {}; if (this.params instanceof Object) Object.assign(params, this.params); if (this.userParams instanceof Object) Object.assign(params, this.userParams); return params; } sendRequest(filter, append) { this.cancelRequest(); this.canceler = this.$q.defer(); let params = Object.assign( {filter: filter}, this.buildParams() ); let options = { timeout: this.canceler.promise, params: params }; return this.$http.get(this._url, options).then( json => this.onRemoteDone(json, filter, append), json => this.onRemoteError(json) ); } onRemoteDone(json, filter, append) { let data = json.data; if (append) { this.orgData = this.orgData.concat(data); } else { this.orgData = data; this.currentFilter = filter; } this.data = this.proxiedData.slice(); this.moreRows = filter.limit && data.length == filter.limit; this.onRequestEnd(); } onRemoteError(err) { this.onRequestEnd(); throw err; } onRequestEnd() { this.canceler = null; } undoChanges() { super.undoChanges(); this.data = this.proxiedData.slice(); } } CrudModel.$inject = ['$q', '$http']; ngModule.component('vnCrudModel', { controller: CrudModel, bindings: { orgData: '