UNPKG

cheetah-framework

Version:

Cheetah Framework JS used in all our applications

194 lines (163 loc) 4.37 kB
import FormErrorHelper from './FormErrorHelper' import FormErrors from './errors' import VueScrollTo from 'vue-scrollto' import LaravelModel from '@cheetah/models/LaravelModel' Vue.config.optionMergeStrategies.form = function (toVal, fromVal) { return _.defaults(fromVal, toVal) } const formDefaultOptions = { /** * Override method used to save instance. * By default, store and update method will be used. */ storeMethodName: 'store', updateMethodName: 'update' } export default { form: formDefaultOptions, provide () { const _this = this return { formErrors: _this.formErrors } }, mixins: [FormErrorHelper], props: { instance: { type: LaravelModel, required: true } }, data () { return { loading: true, saving: false, formErrors: new FormErrors(), localInstance: null, savePromise: Promise.resolve() } }, computed: { canNotSave () { return this.loading || this.saving }, canNotCancel () { return this.saving }, isPersisted () { return this.instance.isPersisted } }, methods: { handleError (error) { if (!error) { return } if (error.response) { this.formErrors.set(error.response.data.errors) this.$nextTick(() => { if (!this.scrollToFirstError()) { // Fallback error reporting when there are errors, but they are not visible. RemoteErrors(error) } }) } else { RemoteErrors(error) } throw error }, scrollToFirstError, /** * Use it to bind save action on a click button event. Prevent, * el-button to react with Promise and throw a weird error. Use * saveInstance if you support Promise. */ callSaveMethod () { this.saveInstance() }, saveInstance () { this.saving = true this.formErrors.forget() const calledMethod = this.$options.form[this.localInstance.isPersisted ? 'updateMethodName' : 'storeMethodName'] return (this.savePromise = this.localInstance[calledMethod]().then(response => { this.$emit('saved', response.data) return response }).catch(this.handleError).finally(_ => { this.saving = false })) }, load () { const Constructor = this.instance.constructor let promises = this.promisesToWaitingFor() if (promises instanceof Promise) { promises = [promises] } this.loading = true this.localInstance = null if (this.instance.isPersisted) { promises.push(Constructor.get(this.instance[Constructor.idKey]).then(response => { this.localInstance = new Constructor(response.data) this.$emit('loaded', this.localInstance) })) } else { this.localInstance = new Constructor(this.instance) } Promise.all(promises).finally(_ => { this.afterLoad() this.loading = false }) }, /** * Use it to return Promises your need to wait for * to display your form. * Can be a Promise or an array of Promises * @returns {Promise<void>[]|Promise<void>} */ promisesToWaitingFor () { return [] }, /** * Override this function to do something after everything is loaded */ afterLoad () { }, /** * Override this function to do something after save success */ afterSave () { } }, created () { this.load() } } function scrollToFirstError () { let container, offset if (this.$el) { container = this.$el offset = 0 } else { container = document offset = _.get(document.getElementsByClassName('c-header'), '0.offsetHeight') || 0 } const firstError = container.querySelector('.is-error, .inlineError') if (!firstError) { return false } // @todo - If in modal, scroll in modal (scroll not supported yet in modal) let errorInput = firstError.querySelector('input') if (!errorInput) { errorInput = firstError.querySelector('textarea') } if (errorInput) { errorInput.focus() } if (offset !== null) { VueScrollTo.scrollTo(firstError, 600, { container, easing: 'ease', offset: (offset * -1) - 30 }) return true } return false } export { scrollToFirstError }