salix/front/core/components/crud-model/crud-model.js

316 lines
7.7 KiB
JavaScript
Raw Normal View History

import ngModule from '../../module';
import ModelProxy from '../model-proxy/model-proxy';
2018-12-27 11:54:16 +00:00
import {mergeWhere, mergeFilters} from 'vn-loopback/util/filter';
2018-10-23 10:14:47 +00:00
/**
* Model that uses remote loopback model as datasource.
*
* @property {Array<String>} fields the list of fields to fetch
*/
export default class CrudModel extends ModelProxy {
2018-10-22 06:23:10 +00:00
constructor($q, $http, $element, $scope) {
super($element, $scope);
this.$http = $http;
this.$q = $q;
this.primaryKey = 'id';
this.autoLoad = false;
this.page = 1;
}
2018-10-18 07:24:20 +00:00
$onInit() {
2018-10-22 06:23:10 +00:00
this.initialized = true;
2018-10-18 07:24:20 +00:00
this.autoRefresh();
}
get isLoading() {
return this.canceler != null;
}
2018-10-23 10:14:47 +00:00
/**
* @type {String} The remote model URL
*/
get url() {
return this._url;
}
2018-10-18 07:24:20 +00:00
set url(url) {
if (this._url === url) return;
this._url = url;
this.clear();
2018-10-22 06:23:10 +00:00
if (this.initialized)
this.autoRefresh();
2018-10-18 07:24:20 +00:00
}
autoRefresh() {
if (this.autoLoad)
2018-10-18 07:24:20 +00:00
return this.refresh();
return this.$q.resolve();
}
2018-09-05 11:01:21 +00:00
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,
2018-09-05 11:01:21 +00:00
order: order,
2018-07-09 16:06:25 +00:00
limit: this.limit
};
let filter = this.filter;
filter = mergeFilters(myFilter, filter);
2018-09-05 11:01:21 +00:00
filter = mergeFilters(this.userFilter, filter);
return filter;
}
2018-09-05 11:01:21 +00:00
refresh() {
2018-10-18 07:24:20 +00:00
if (!this._url)
return this.$q.resolve();
2018-09-05 11:01:21 +00:00
return this.sendRequest(this.buildFilter());
}
2018-09-05 11:01:21 +00:00
/**
* Applies a new filter to the model.
*
2018-10-23 10:14:47 +00:00
* @param {Object} filter The Loopback filter
* @param {Object} params Custom parameters
2018-09-05 11:01:21 +00:00
* @return {Promise} The request promise
*/
2018-10-23 10:14:47 +00:00
applyFilter(filter, params) {
this.userFilter = filter;
this.userParams = params;
2018-09-05 11:01:21 +00:00
return this.refresh();
}
2018-09-05 11:01:21 +00:00
/**
* Adds a filter to the model.
*
2018-10-23 10:14:47 +00:00
* @param {Object} filter The Loopback filter
* @param {Object} params Custom parameters
2018-09-05 11:01:21 +00:00
* @return {Promise} The request promise
*/
2018-10-23 10:14:47 +00:00
addFilter(filter, params) {
this.userFilter = mergeFilters(filter, this.userFilter);
this.userParams = Object.assign({}, this.userParams, params);
2018-09-05 11:01:21 +00:00
return this.refresh();
}
/**
* Applies a new filter to the model.
*
* @param {Object} params Custom parameters
* @return {Promise} The request promise
*/
applyParams(params) {
this.userParams = params;
return this.refresh();
}
2018-09-05 11:01:21 +00:00
removeFilter() {
2020-02-17 12:50:54 +00:00
return this.applyFilter(null, null);
}
2018-09-05 11:01:21 +00:00
/**
* Cancels the current request, if any.
*/
cancelRequest() {
if (this.canceler) {
this.canceler.resolve();
this.canceler = null;
}
}
loadMore(append) {
2018-10-18 07:24:20 +00:00
if (!this.moreRows)
return this.$q.resolve();
const filter = Object.assign({}, this.currentFilter);
if (append)
filter.skip = this.orgData ? this.orgData.length : 0;
if (!append) {
this.page += 1;
filter.limit = this.page * this.limit;
}
return this.sendRequest(filter, append);
2018-10-18 07:24:20 +00:00
}
clear() {
this.orgData = null;
2018-11-29 07:09:40 +00:00
this.moreRows = null;
}
getChanges() {
if (!this.isChanged) return null;
2018-10-18 07:24:20 +00:00
const deletes = [];
const updates = [];
const creates = [];
const pk = this.primaryKey;
for (let row of this.removed)
deletes.push(row.$orgRow[pk]);
2020-02-06 06:41:51 +00:00
for (let row of this.data) {
2018-10-18 07:24:20 +00:00
if (row.$isNew) {
let data = {};
2018-11-29 07:09:40 +00:00
for (let prop in row) {
2018-10-18 07:24:20 +00:00
if (prop.charAt(0) !== '$')
data[prop] = row[prop];
2018-11-29 07:09:40 +00:00
}
2020-02-06 06:41:51 +00:00
creates.push(row);
2018-10-18 07:24:20 +00:00
} else if (row.$oldData) {
let data = {};
for (let prop in row.$oldData)
data[prop] = row[prop];
updates.push({
data,
where: {[pk]: row.$orgRow[pk]}
});
2018-10-18 07:24:20 +00:00
}
2018-11-29 07:09:40 +00:00
}
2023-01-05 09:35:42 +00:00
const changes = {deletes, updates, creates};
2018-11-29 07:09:40 +00:00
for (let prop in changes) {
if (changes[prop].length === 0)
changes[prop] = undefined;
2018-11-29 07:09:40 +00:00
}
return changes;
}
/**
* Saves current changes on the server.
*
* @return {Promise} The save request promise
*/
save() {
const pk = this.primaryKey;
const changes = this.getChanges();
if (!changes) return this.$q.resolve();
2023-01-05 09:35:42 +00:00
const creates = changes.creates || [];
2018-10-18 07:24:20 +00:00
let url = this.saveUrl ? this.saveUrl : `${this._url}/crud`;
return this.$http.post(url, changes)
2020-02-06 06:41:51 +00:00
.then(res => {
2020-02-06 09:43:46 +00:00
const created = res.data;
2020-02-06 06:41:51 +00:00
// Apply new data to created instances
for (let i = 0; i < creates.length; i++) {
const row = creates[i];
2020-02-06 06:41:51 +00:00
row[pk] = created[i][pk];
for (let prop in row) {
if (prop.charAt(0) !== '$')
row[prop] = created[i][prop];
}
}
2018-10-30 14:08:19 +00:00
this.applyChanges();
super.save();
});
}
2018-09-05 11:01:21 +00:00
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();
this.isPaging = append;
2019-10-04 22:23:34 +00:00
if (!append)
2019-10-04 22:23:34 +00:00
this.status = 'loading';
2018-09-05 11:01:21 +00:00
let params = Object.assign(
{filter},
2018-09-05 11:01:21 +00:00
this.buildParams()
);
let options = {
timeout: this.canceler.promise,
params: params
};
2018-10-18 07:24:20 +00:00
return this.$http.get(this._url, options).then(
2018-09-05 11:01:21 +00:00
json => this.onRemoteDone(json, filter, append),
json => this.onRemoteError(json, append)
).finally(() => {
this.isPaging = false;
});
2018-09-05 11:01:21 +00:00
}
onRemoteDone(json, filter, append) {
let data = json.data;
2018-10-30 14:08:19 +00:00
if (append)
2018-09-05 11:01:21 +00:00
this.orgData = this.orgData.concat(data);
2018-10-30 14:08:19 +00:00
else {
2018-09-05 11:01:21 +00:00
this.orgData = data;
this.currentFilter = filter;
}
2018-10-18 07:24:20 +00:00
this.data = this.proxiedData.slice();
2018-09-05 11:01:21 +00:00
this.moreRows = filter.limit && data.length == filter.limit;
this.onRequestEnd();
}
onRemoteError(err, append) {
if (!append) {
this.clear();
this.status = 'error';
}
2018-09-05 11:01:21 +00:00
this.onRequestEnd();
throw err;
}
onRequestEnd() {
this.canceler = null;
}
2018-10-18 07:24:20 +00:00
undoChanges() {
super.undoChanges();
this.data = this.proxiedData.slice();
}
}
2018-10-22 06:23:10 +00:00
CrudModel.$inject = ['$q', '$http', '$element', '$scope'];
2020-07-24 15:46:06 +00:00
ngModule.vnComponent('vnCrudModel', {
controller: CrudModel,
bindings: {
orgData: '<?',
data: '=?',
2018-07-02 09:52:50 +00:00
onDataChange: '&?',
link: '<?',
url: '@?',
saveUrl: '@?',
2018-10-18 07:24:20 +00:00
fields: '<?',
include: '<?',
2018-10-18 07:24:20 +00:00
where: '<?',
order: '@?',
limit: '<?',
filter: '<?',
2018-09-05 11:01:21 +00:00
params: '<?',
userFilter: '<?',
2018-07-09 16:06:25 +00:00
userParams: '<?',
primaryKey: '@?',
2018-10-30 14:08:19 +00:00
autoLoad: '<?',
autoSave: '<?'
}
});