Last active
March 3, 2020 19:16
-
-
Save dbollinger/1fa62ee975ba852633326355d409f7ca to your computer and use it in GitHub Desktop.
ember form component with yup validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Component from '@ember/component'; | |
import EmberObject from '@ember/object'; | |
import layout from '../templates/components/ember-form'; | |
/** | |
* @class EmberForm | |
* @namespace Components | |
* | |
* ```hbs | |
* <EmberForm @onSubmit={{action "submitMyForm"}} @formSchema={{myFormSchema}} as |form|> | |
* ... | |
* </EmberForm> | |
* ``` | |
* @class EmberForm | |
* @yield {Hash} form | |
* @yield {EmberObject} form.errors | |
* @yield {Action} form.updateField | |
* @yield {Action} form.validateField | |
* @yield {Action} form.validateForm | |
* @yield {Component} form.submit | |
*/ | |
export default Component.extend({ | |
layout, | |
tagName: null, | |
/** | |
* A yup schema validation object. | |
* | |
* @argument formSchema | |
* @type ValidationSchema | |
*/ | |
formSchema: null, | |
/** | |
* The initial data to populate the form. | |
* | |
* @property formSchema | |
* @type EmberObject | |
*/ | |
data: null, | |
/** | |
* @property formset | |
* @type EmberObject | |
*/ | |
formset: null, | |
/** | |
* @property formErrors | |
* @type EmberObject | |
*/ | |
formErrors: null, | |
init() { | |
this._super(...arguments); | |
this.initForm(); | |
}, | |
/** | |
* @method initForm | |
*/ | |
initForm() { | |
let formset = this.data ? EmberObject.create({ ...this.data }) : EmberObject.create(); | |
this.set('formset', formset); | |
this.set('formErrors', EmberObject.create()); | |
}, | |
/** | |
* A method to validate a single field in the formset against the formSchema | |
* | |
* @method validateField | |
* @param {string} field | |
*/ | |
async validateField(field) { | |
try { | |
let result = await this.formSchema.validateAt(field, this.formset); | |
this.formset.set(field, result); | |
this.formErrors.set(field, null); | |
} catch(e) { | |
this.formErrors.set(field, e); | |
} | |
}, | |
/** | |
* @method validateForm | |
*/ | |
async validateForm() { | |
try { | |
let result = await this.formSchema.validate(this.formset, { abortEarly: false }); | |
this.set('formErrors', EmberObject.create()); | |
return result; | |
} catch(e) { | |
this.set('formErrors', e.inner.reduce((errors, error) => { | |
errors.set(error.path, error); | |
return errors; | |
}, EmberObject.create())); | |
return e; | |
} | |
}, | |
actions: { | |
updateField(field, value) { | |
if (value === null) { | |
// This is messy, but is handling an edge case for clearing the date input. Alternate options? | |
this.send('clearField', field); | |
} else { | |
this.formset.set(field, value); | |
// We can probably come up with a better rule to determine when to validate | |
if (this.formErrors[field]) { | |
this.validateField(field); | |
} | |
} | |
}, | |
validateField(field) { | |
this.validateField(field); | |
}, | |
validateForm() { | |
// I don't think this action would be necessary very often, | |
// But gives some extra flexibility to the consuming application. | |
return this.validateForm(); | |
}, | |
clearField(field) { | |
delete this.formset[field]; | |
this.validateField(field); | |
}, | |
submitForm() { | |
// Raise the submit action with the formset | |
this.validateForm().then(() => { | |
let result = this.onSubmit(this.formset); | |
}, (errors) => { | |
console.log('Validation Errors', errors); | |
}); | |
}, | |
revertForm() { | |
this.initForm(); | |
} | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Controller from '@ember/controller'; | |
import * as yup from 'yup'; | |
export const projectSchema = yup.object().shape({ | |
projectName: yup.string().required().trim().min(10).label('Project Name'), | |
hasDeadline: yup.boolean().label('Has Deadline'), | |
deadline: yup.date().label('Deadline') | |
.when('hasDeadline', { | |
is: true, | |
then: yup.date().required() | |
}), | |
}); | |
export default Controller.extend({ | |
init() { | |
this._super(...arguments); | |
this.set('formSchema', projectSchema); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment