/**
This module has two mixins: godForm and formComponent, they are used to manage form handler
@module mixins
@submodule form
*/
import { action, get, setProperties } from '@ember/object';
import { inject, inject as service } from '@ember/service';
import { isNone } from '@ember/utils';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { A } from '@ember/array';
/**
delete object from backend server
@event deleteObject
@param {Object} selectedItem The current selected item
*/
let deleteObject = function (selectedItem) {
if (!this.modelName) {
throw new Error(`mixin component modelName is invalid: ${this.modelName}`);
}
this.loading = true;
this.store
.deleteRecord(this.modelName, selectedItem)
.then((data) => {
this.loading = false;
this.success('delete', data, selectedItem);
})
.catch((reason) => {
this.loading = false;
this.fail('delete', reason, selectedItem);
});
};
/**
GodForm is used for data list to create, update and delete children object
only support native style class component
@public
@class godForm
**/
class GodForm extends Component {
constructor() {
super(...arguments);
this.model = this.args.model ? this.args.model : A();
}
@service store;
/**
@property modelName
@type String
*/
modelName = '';
/**
for loading
@property loading
@type boolean
*/
@tracked loading = false;
/**
data set, normally array
@property model
@type Object
*/
@tracked model = null;
/**
current selected item
@property selectedItem
@type Object
*/
@tracked selectedItem = null;
/**
for modal dialog
@property modalShow
@type boolean
*/
@tracked modalShow = false;
/**
ajax fail reason
@property reason
@type String
*/
@tracked reason = null;
/**
orm store service
@property store
@type Object
*/
@inject store;
/**
create new record according to modelName
@event add
*/
@action
add() {
this.modalShow = true;
this.selectedItem = this.store.createRecord(this.modelName);
}
/**
edit current selected item
@event edit
@param {Object} selectedItem
*/
@action
edit(selectedItem) {
this.modalShow = true;
if (!isNone(selectedItem)) {
this.selectedItem = selectedItem;
}
}
/**
cancel current operation
@event cancel
*/
@action
cancel() {
this.modalShow = false;
}
/**
remove current selected item
@event remove
@param {Object} selectedItem
*/
@action
remove(selectedItem) {
if (!this.modelName) {
throw new Error(
`mixin component modelName is invalid: ${this.modelName}`
);
}
this.loading = true;
this.store
.deleteRecord(this.modelName, selectedItem)
.then((data) => {
console.log(data, selectedItem);
this.loading = false;
this.success('delete', data, selectedItem);
})
.catch((reason) => {
this.loading = false;
this.fail('delete', reason, selectedItem);
});
}
/**
success ajax request success callback
@event success
@params {String} action The current operation: create, update, delete
@params {Object} data The response data from backend server
@params {Object} selectedItem Thc current selected item
*/
@action
success(action, data, selectedItem) {
this.modalShow = false;
if (this.args?.success) {
this.args.success(action, data, selectedItem);
}
// child component send action to parent
if (action === 'delete') {
this.model.removeObject(selectedItem);
return;
}
if (!this.model.includes(selectedItem)) {
this.model.insertAt(0, selectedItem);
}
}
/**
fail ajax request success callback
@event fail
@params {string} action The current operation: create, update, delete
@params {Object} reason The ajax request response
@params {Object} selectedItem Thc current selected item
*/
@action
fail(action, reason, selectedItem) {
this.reason = reason;
// check parent callback
if (this.args?.fail) {
this.args.fail(action, reason, selectedItem);
}
}
}
/**
Form is used for one record to create, update and delete
only support native style class component
@public
@class Form
**/
class Form extends Component {
constructor() {
super(...arguments);
this.model = this.args.model ? this.args.model : null;
}
/**
@property modelName
@type String
*/
modelName = '';
/**
single object, normally for form
@property model
@type Object
*/
@tracked model = null;
/**
orm store service
@property store
@type Object
*/
@inject store;
/**
ajax fail reason
@property reason
@type String
*/
@tracked reason = null;
@tracked loading = false;
/**
save triggle when user click save action
@event save
*/
@action
save() {
if (!this.modelName) {
throw new Error(`FormComponent modelName is invalid: ${this.modelName}`);
}
this.loading = true;
if (!this.validate()) {
return;
}
let primaryKey = this.store.modelFor(this.modelName).primaryKey;
let actionName = get(this.model, primaryKey) ? 'update' : 'create';
this.store
.save(this.modelName, this.model)
.then((data) => {
this.loading = false;
this.success(actionName, data);
})
.catch((reason) => {
this.loading = false;
this.fail(actionName, reason);
});
}
/**
delete triggle when user click save action
@event remove
*/
@action
remove() {
deleteObject.call(this, this.model);
}
/**
success ajax request success callback
@event succuess
@params {String} action The current operation: create, update, delete
@params {Object} data The response data from backend server
*/
@action
success(action, data) {
if ((action === 'create' || action === 'update') && data) {
setProperties(this.model, data);
}
if (this.args.success) {
this.args.success(action, data, this.model);
}
}
/**
fail ajax request success callback
@event fail
@params {string} action The current operation: create, update, delete
@params {Object} reason The ajax request response
*/
@action
fail(action, reason) {
this.reason = reason;
// call object fail function from action
if (this.args.fail) {
this.args.fail(action, reason, this.model);
}
}
/**
cancel current operation
@event cancel
*/
@action
cancel() {
if (this.args.cancel) {
this.args.cancel(this.model);
}
}
/**
validate current model
@method validate
@return {Boolean} Returns true when success, false when fails
*/
validate() {
console.log('subclass override this function for model validate');
return true;
}
}
export { GodForm, Form };