salix/front/core/components/watcher/watcher.js

282 lines
7.2 KiB
JavaScript
Raw Normal View History

2018-02-10 15:18:01 +00:00
import ngModule from '../../module';
import Component from '../../lib/component';
import getModifiedData from '../../lib/modified';
import copyObject from '../../lib/copy';
import isEqual from '../../lib/equals';
import isFullEmpty from '../../lib/full-empty';
import UserError from '../../lib/user-error';
/**
* Component that checks for changes on a specific model property and
* asks the user to save or discard it when the state changes.
* Also it can save the data to the server when the @url and @idField
* properties are provided.
*/
export default class Watcher extends Component {
2019-01-30 12:32:25 +00:00
constructor($element, $, $state, $stateParams, $transitions, $http, vnApp, $translate, $attrs, $q) {
super($element);
2019-01-30 12:32:25 +00:00
Object.assign(this, {
$,
$state,
$stateParams,
$http,
_: $translate,
$attrs,
vnApp,
$q
});
this.state = null;
this.deregisterCallback = $transitions.onStart({},
transition => this.callback(transition));
2017-10-05 07:31:28 +00:00
this.updateOriginalData();
}
$onInit() {
if (this.get && this.url)
this.fetchData();
else if (this.get && !this.url)
throw new Error('URL parameter ommitted');
}
2019-09-18 07:41:25 +00:00
$onChanges() {
if (this.data)
2017-10-05 07:31:28 +00:00
this.updateOriginalData();
}
$onDestroy() {
this.deregisterCallback();
}
get dirty() {
return this.form && this.form.$dirty || this.dataChanged();
}
dataChanged() {
let data = this.copyInNewObject(this.data);
return !isEqual(data, this.orgData);
}
fetchData() {
let id = this.data[this.idField];
return this.$http.get(`${this.url}/${id}`).then(
2017-09-28 09:29:01 +00:00
json => {
2017-10-05 07:20:40 +00:00
this.data = copyObject(json.data);
2017-10-05 07:31:28 +00:00
this.updateOriginalData();
2017-09-28 09:29:01 +00:00
}
);
}
2018-02-08 12:13:42 +00:00
2017-03-07 16:11:56 +00:00
/**
* Submits the data and goes back in the history.
2018-02-08 12:13:42 +00:00
*
* @return {Promise} The request promise
2017-03-07 16:11:56 +00:00
*/
submitBack() {
return this.submit().then(res => {
this.window.history.back();
return res;
});
2017-03-07 16:11:56 +00:00
}
2018-02-08 12:13:42 +00:00
2017-06-03 11:01:47 +00:00
/**
* Submits the data and goes another state.
*
* @param {String} state The state name
2018-02-08 12:13:42 +00:00
* @param {Object} params The request params
* @return {Promise} The request promise
2017-06-03 11:01:47 +00:00
*/
2017-12-04 07:17:29 +00:00
submitGo(state, params) {
return this.submit().then(res => {
this.$state.go(state, params || {});
return res;
});
2017-06-03 11:01:47 +00:00
}
2018-02-08 12:13:42 +00:00
2017-03-07 16:11:56 +00:00
/**
* Submits the data to the server.
*
* @return {Promise} The http request promise
*/
submit() {
try {
2020-03-10 13:09:26 +00:00
if (this.requestMethod() !== 'post')
this.check();
else this.isInvalid();
} catch (err) {
return this.$q.reject(err);
}
return this.realSubmit().then(res => {
this.notifySaved();
return res;
});
}
/**
* Submits the data without checking data validity or changes.
*
* @return {Promise} The http request promise
*/
realSubmit() {
if (this.form)
2017-03-07 16:11:56 +00:00
this.form.$setSubmitted();
2020-03-10 13:09:26 +00:00
const isPost = (this.requestMethod() === 'post');
if (!this.dataChanged() && !isPost) {
this.updateOriginalData();
return this.$q.resolve();
}
2018-02-21 10:09:27 +00:00
let changedData = isPost
2018-05-24 14:09:32 +00:00
? this.data
2018-02-08 11:57:57 +00:00
: getModifiedData(this.data, this.orgData);
2017-02-21 10:36:43 +00:00
let id = this.idField ? this.orgData[this.idField] : null;
// If watcher is associated to mgCrud
2018-02-01 12:28:45 +00:00
if (this.save && this.save.accept) {
if (id)
changedData[this.idField] = id;
this.save.model = changedData;
return this.$q((resolve, reject) => {
2017-02-21 10:36:43 +00:00
this.save.accept().then(
json => this.writeData({data: json}, resolve),
reject
2017-02-21 10:36:43 +00:00
);
});
}
// When mgCrud is not used
if (id) {
return this.$q((resolve, reject) => {
2017-06-03 11:01:47 +00:00
this.$http.patch(`${this.url}/${id}`, changedData).then(
2017-02-07 16:02:17 +00:00
json => this.writeData(json, resolve),
reject
);
});
}
return this.$q((resolve, reject) => {
2018-02-01 12:28:45 +00:00
this.$http.post(this.url, changedData).then(
json => this.writeData(json, resolve),
reject
);
});
}
2020-03-11 11:03:55 +00:00
/**
* return the request method.
*/
2020-03-10 13:09:26 +00:00
requestMethod() {
return this.$attrs.save && this.$attrs.save.toLowerCase();
}
/**
* Checks if data is ready to send.
*/
check() {
if (this.form && this.form.$invalid)
2019-01-25 14:09:29 +00:00
throw new UserError('Some fields are invalid');
if (!this.dirty)
2019-01-25 14:09:29 +00:00
throw new UserError('No changes to save');
2017-02-07 16:02:17 +00:00
}
2020-03-10 13:09:26 +00:00
/**
2020-03-11 11:03:55 +00:00
* Checks if the form is valid.
2020-03-10 13:09:26 +00:00
*/
isInvalid() {
if (this.form && this.form.$invalid)
throw new UserError('Some fields are invalid');
}
/**
* Notifies the user that the data has been saved.
*/
notifySaved() {
this.vnApp.showSuccess(this.$t('Data saved!'));
2017-02-21 10:36:43 +00:00
}
setPristine() {
if (this.form) this.form.$setPristine();
}
setDirty() {
if (this.form) this.form.$setDirty();
}
callback(transition) {
if (!this.state && this.dirty) {
this.state = transition.to().name;
this.$.confirm.show();
return false;
}
return true;
}
onConfirmResponse(response) {
2019-10-30 15:57:14 +00:00
if (response === 'accept') {
if (this.data)
Object.assign(this.data, this.orgData);
this.$state.go(this.state);
2018-11-06 12:59:16 +00:00
} else
this.state = null;
}
writeData(json, resolve) {
Object.assign(this.data, json.data);
this.updateOriginalData();
resolve(json);
2017-02-21 10:36:43 +00:00
}
2017-10-05 07:31:28 +00:00
updateOriginalData() {
this.orgData = this.copyInNewObject(this.data);
this.setPristine();
}
2019-09-18 07:41:25 +00:00
loadOriginalData() {
const orgData = JSON.parse(JSON.stringify(this.orgData));
this.data = Object.assign(this.data, orgData);
2019-09-18 07:41:25 +00:00
this.setPristine();
}
2017-10-05 07:31:28 +00:00
copyInNewObject(data) {
let newCopy = {};
if (data && typeof data === 'object') {
Object.keys(data).forEach(
2018-09-24 08:43:54 +00:00
key => {
let value = data[key];
if (value instanceof Date)
newCopy[key] = new Date(value.getTime());
else if (!isFullEmpty(value)) {
if (typeof value === 'object')
newCopy[key] = this.copyInNewObject(value);
else
newCopy[key] = value;
2017-10-05 07:20:40 +00:00
}
}
);
}
2018-11-06 12:59:16 +00:00
2017-10-05 07:31:28 +00:00
return newCopy;
}
}
2019-01-30 12:32:25 +00:00
Watcher.$inject = ['$element', '$scope', '$state', '$stateParams', '$transitions', '$http', 'vnApp', '$translate', '$attrs', '$q'];
2018-02-10 15:18:01 +00:00
ngModule.component('vnWatcher', {
2017-05-31 08:28:39 +00:00
template: require('./watcher.html'),
bindings: {
url: '@?',
idField: '@?',
data: '<',
2017-02-21 10:36:43 +00:00
form: '<',
save: '<',
get: '<?'
},
controller: Watcher
});