import {Component} from '../../vues6.js' import {Status} from './Listing.component.js' import {Resource, ResourceActions} from '../Resource.js' import {uuid} from '../util.js' const template = `
{{ title }}
Loading...
{{ field.helpText }} {{ errors[field.key] }}
{{ statusMessage }}
` export class FormComponent extends Component { static get selector() { return 'cobalt-form' } static get template() { return template } static get props() { return ['resourcekey', 'resourceid', 'resourcemode'] } constructor() { super() this.status = Status.loading this.title = 'Loading...' this.statusMessage = 'Loading...' this.fields = [] this.data = {} this.actions = [] this.unregister = [] this.mode = 'edit' this.id = uuid() this.internalResourceId = 0 this.errors = {} /** @var {Resource} */ this.resource = undefined } async vue_on_create() { this.resource = await Resource.get(this.resourcekey) this.title = this.resource.singular() this.mode = this.resourcemode || this.mode this.internalResourceId = this.resourceid || this.internalResourceId if ( !this.resource.supports(ResourceActions.readOne) ) { this.status = Status.errorUnsupported } await this.load() console.log('form', this) } async load() { this.data = this.internalResourceId ? await this.resource.readOne(this.internalResourceId) : {} this.fields = [...this.resource.configuration.fields] this.fields.forEach(field => { if ( field.type === 'date' && this.data[field.key] ) { this.data[field.key] = new Date(this.data[field.key]) } }) if ( this.resource.configuration.display.field ) { this.title = this.resource.singular() if ( this.internalResourceId ) this.title = `${this.title}: ${this.data[this.resource.configuration.display.field]}` } this.status = Status.ready this.statusMessage = '' } async save() { if ( !this.validate() ) return; this.statusMessage = 'Saving...' const values = {} this.fields.forEach(field => { let value = this.data[field.key] const isUndef = !value && !(['integer', 'number'].includes(field.type) && value === 0) if ( isUndef ) return; if ( field.type === 'number' ) value = parseFloat(String(value)) if ( field.type === 'integer' ) value = parseInt(String(value), 10) if ( field.type === 'date' ) value = value.toISOString() values[field.key] = value }) if ( this.internalResourceId ) { await this.resource.update(this.internalResourceId, values) } else { const result = await this.resource.create(values) this.internalResourceId = result[this.resource.configuration.primaryKey] history.replaceState({}, document.getElementsByTagName('title')[0].innerText, `${location.protocol}//${location.host}/dash/cobalt/form/${this.resource.key}/${this.internalResourceId}`) } await this.load() this.statusMessage = `${this.resource.singular()} ${this.mode === 'insert' ? 'created' : 'saved'}` this.mode = 'edit' setTimeout(() => this.statusMessage = '', 7000) } validate() { let pass = true this.fields.forEach(field => this.errors[field.key] = undefined) this.fields.forEach(field => { // FIXME select const value = this.data[field.key] const isUndef = !value && !(['integer', 'number'].includes(field.type) && value === 0) if ( field.required && isUndef ) { this.errors[field.key] = 'This field is required' pass = false return } if ( field.type === 'date' && !isUndef && isNaN(value.getHours()) ) { this.errors[field.key] = `Invalid ${field.renderer || 'date'}` pass = false return } if ( field.type === 'number' && !isUndef && isNaN(parseFloat(String(value))) ) { this.errors[field.key] = 'Invalid number' pass = false return } if ( field.type === 'integer' && !isUndef && (isNaN(parseInt(String(value), 10)) || parseFloat(String(value)) !== parseInt(String(value), 10)) ) { this.errors[field.key] = 'Invalid integer' pass = false return } }) this.$nextTick(() => this.$forceUpdate()) return pass } }