Fixes form submissions, and a bug that prevented value props from populating forms
This commit is contained in:
parent
d7e3859951
commit
839f0936ed
2
dist/formulate.esm.js
vendored
2
dist/formulate.esm.js
vendored
@ -1776,7 +1776,7 @@ var script$1 = {
|
||||
this.$emit('submit-raw', submission);
|
||||
submission.hasValidationErrors()
|
||||
.then(function (hasErrors) { return hasErrors ? false : submission.values(); })
|
||||
.then(function (json) { return this$1.$emit('submit', json); });
|
||||
.then(function (json) { return json !== false ? this$1.$emit('submit', json) : null; });
|
||||
},
|
||||
showErrors: function showErrors () {
|
||||
for (var fieldName in this.registry) {
|
||||
|
2
dist/formulate.min.js
vendored
2
dist/formulate.min.js
vendored
@ -1779,7 +1779,7 @@ var Formulate = (function (exports, isUrl, nanoid, isPlainObject) {
|
||||
this.$emit('submit-raw', submission);
|
||||
submission.hasValidationErrors()
|
||||
.then(function (hasErrors) { return hasErrors ? false : submission.values(); })
|
||||
.then(function (json) { return this$1.$emit('submit', json); });
|
||||
.then(function (json) { return json !== false ? this$1.$emit('submit', json) : null; });
|
||||
},
|
||||
showErrors: function showErrors () {
|
||||
for (var fieldName in this.registry) {
|
||||
|
2
dist/formulate.umd.js
vendored
2
dist/formulate.umd.js
vendored
@ -1782,7 +1782,7 @@
|
||||
this.$emit('submit-raw', submission);
|
||||
submission.hasValidationErrors()
|
||||
.then(function (hasErrors) { return hasErrors ? false : submission.values(); })
|
||||
.then(function (json) { return this$1.$emit('submit', json); });
|
||||
.then(function (json) { return json !== false ? this$1.$emit('submit', json) : null; });
|
||||
},
|
||||
showErrors: function showErrors () {
|
||||
for (var fieldName in this.registry) {
|
||||
|
2
dist/snow.css
vendored
2
dist/snow.css
vendored
@ -1,5 +1,5 @@
|
||||
.formulate-input {
|
||||
margin-bottom: 2em; }
|
||||
margin-bottom: 1.5em; }
|
||||
.formulate-input .formulate-input-label {
|
||||
display: block;
|
||||
line-height: 1.5;
|
||||
|
4
dist/snow.min.css
vendored
4
dist/snow.min.css
vendored
File diff suppressed because one or more lines are too long
@ -26,10 +26,10 @@ export default class FormSubmission {
|
||||
values () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const pending = []
|
||||
const values = cloneDeep(this.form.internalModelProxy)
|
||||
const values = cloneDeep(this.form.internalFormModelProxy)
|
||||
for (const key in values) {
|
||||
if (typeof this.form.internalModelProxy[key] === 'object' && this.form.internalModelProxy[key] instanceof FileUpload) {
|
||||
pending.push(this.form.internalModelProxy[key].upload())
|
||||
if (typeof this.form.internalFormModelProxy[key] === 'object' && this.form.internalFormModelProxy[key] instanceof FileUpload) {
|
||||
pending.push(this.form.internalFormModelProxy[key].upload())
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -85,11 +85,20 @@ export default {
|
||||
},
|
||||
register (field, component) {
|
||||
this.registry[field] = component
|
||||
if (!component.$options.propsData.hasOwnProperty('formulateValue') && this.hasFormulateValue && this.formulateValue[field]) {
|
||||
const hasVModelValue = Object.prototype.hasOwnProperty.call(component.$options.propsData, 'formulateValue')
|
||||
const hasValue = Object.prototype.hasOwnProperty.call(component.$options.propsData, 'value')
|
||||
if (
|
||||
!hasVModelValue &&
|
||||
this.hasFormulateValue &&
|
||||
this.formulateValue[field]
|
||||
) {
|
||||
// In the case that the form is carrying an initial value and the
|
||||
// element is not, set it directly.
|
||||
component.context.model = this.formulateValue[field]
|
||||
} else if (component.$options.propsData.hasOwnProperty('formulateValue') && !shallowEqualObjects(component.internalModelProxy, this.formulateValue[field])) {
|
||||
} else if (
|
||||
(hasVModelValue || hasValue) &&
|
||||
!shallowEqualObjects(component.internalModelProxy, this.formulateValue[field])
|
||||
) {
|
||||
this.setFieldValue(field, component.internalModelProxy)
|
||||
}
|
||||
},
|
||||
@ -98,9 +107,9 @@ export default {
|
||||
this.showErrors()
|
||||
const submission = new FormSubmission(this)
|
||||
this.$emit('submit-raw', submission)
|
||||
submission.hasValidationErrors()
|
||||
return submission.hasValidationErrors()
|
||||
.then(hasErrors => hasErrors ? false : submission.values())
|
||||
.then(json => this.$emit('submit', json))
|
||||
.then(json => json !== false ? this.$emit('submit', json) : null)
|
||||
},
|
||||
showErrors () {
|
||||
for (const fieldName in this.registry) {
|
||||
|
@ -203,7 +203,7 @@ export function cloneDeep (obj) {
|
||||
const newObj = {}
|
||||
for (const key in obj) {
|
||||
if (obj[key] instanceof FileUpload || isValueType(obj[key])) {
|
||||
newObj[key] = obj
|
||||
newObj[key] = obj[key]
|
||||
} else {
|
||||
newObj[key] = cloneDeep(obj[key])
|
||||
}
|
||||
|
@ -61,6 +61,20 @@ describe('FormulateForm', () => {
|
||||
expect(wrapper.find('input').element.value).toBe('123')
|
||||
})
|
||||
|
||||
it('lets fields set form initial value with value prop', () => {
|
||||
const wrapper = mount({
|
||||
data () {
|
||||
return {
|
||||
formValues: {}
|
||||
}
|
||||
},
|
||||
template: `<FormulateForm v-model="formValues">
|
||||
<FormulateInput name="name" value="123" />
|
||||
</FormulateForm>`
|
||||
})
|
||||
expect(wrapper.vm.formValues).toEqual({ name: '123' })
|
||||
})
|
||||
|
||||
it('receives updates to form model when individual fields are edited', () => {
|
||||
const wrapper = mount({
|
||||
data () {
|
||||
@ -132,7 +146,7 @@ describe('FormulateForm', () => {
|
||||
})
|
||||
|
||||
|
||||
it('it emits an instance of FormSubmission', async () => {
|
||||
it('emits an instance of FormSubmission', async () => {
|
||||
const wrapper = mount(FormulateForm, {
|
||||
slots: { default: '<FormulateInput type="text" formulate-value="123" name="testinput" />' }
|
||||
})
|
||||
@ -141,7 +155,7 @@ describe('FormulateForm', () => {
|
||||
expect(wrapper.emitted('submit-raw')[0][0]).toBeInstanceOf(FormSubmission)
|
||||
})
|
||||
|
||||
it('it resolves hasValidationErrors to true', async () => {
|
||||
it('resolves hasValidationErrors to true', async () => {
|
||||
const wrapper = mount(FormulateForm, {
|
||||
slots: { default: '<FormulateInput type="text" validation="required" name="testinput" />' }
|
||||
})
|
||||
@ -150,4 +164,15 @@ describe('FormulateForm', () => {
|
||||
const submission = wrapper.emitted('submit-raw')[0][0]
|
||||
expect(await submission.hasValidationErrors()).toBe(true)
|
||||
})
|
||||
|
||||
it('resolves submitted form values to an object', async () => {
|
||||
const wrapper = mount(FormulateForm, {
|
||||
slots: { default: '<FormulateInput type="text" validation="required" name="testinput" value="Justin" />' }
|
||||
})
|
||||
wrapper.find('form').trigger('submit')
|
||||
await flushPromises()
|
||||
const submission = await wrapper.vm.formSubmitted()
|
||||
await flushPromises()
|
||||
expect(submission).toEqual({testinput: 'Justin'})
|
||||
})
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { parseRules, regexForFormat } from '@/libs/utils'
|
||||
import { parseRules, regexForFormat, cloneDeep, isValueType } from '@/libs/utils'
|
||||
import rules from '@/libs/rules'
|
||||
import FileUpload from '@/FileUpload';
|
||||
|
||||
describe('parseRules', () => {
|
||||
it('parses single string rules, returning empty arguments array', () => {
|
||||
@ -83,3 +84,36 @@ describe('regexForFormat', () => {
|
||||
|
||||
it('fails date like YYYY-MM-DD with out of bounds day', () => expect(regexForFormat('YYYY-MM-DD').test('1987-01-32')).toBe(false))
|
||||
})
|
||||
|
||||
describe('isValueType', () => {
|
||||
it('passes on strings', () => expect(isValueType('hello')).toBe(true))
|
||||
|
||||
it('passes on numbers', () => expect(isValueType(123)).toBe(true))
|
||||
|
||||
it('passes on booleans', () => expect(isValueType(false)).toBe(true))
|
||||
|
||||
it('passes on symbols', () => expect(isValueType(Symbol(123))).toBe(true))
|
||||
|
||||
it('passes on null', () => expect(isValueType(null)).toBe(true))
|
||||
|
||||
it('passes on undefined', () => expect(isValueType(undefined)).toBe(true))
|
||||
|
||||
it('fails on pojo', () => expect(isValueType({})).toBe(false))
|
||||
|
||||
it('fails on custom type', () => expect(isValueType(FileUpload)).toBe(false))
|
||||
})
|
||||
|
||||
describe('cloneDeep', () => {
|
||||
it('basic objects stay the same', () => expect(cloneDeep({ a: 123, b: 'hello' })).toEqual({ a: 123, b: 'hello' }))
|
||||
|
||||
it('basic nested objects stay the same', () => {
|
||||
expect(cloneDeep({ a: 123, b: { c: 'hello-world' } }))
|
||||
.toEqual({ a: 123, b: { c: 'hello-world' } })
|
||||
})
|
||||
|
||||
it('simple pojo reference types are re-created', () => {
|
||||
const c = { c: 'hello-world' }
|
||||
const clone = cloneDeep({ a: 123, b: c })
|
||||
expect(clone.b === c).toBe(false)
|
||||
})
|
||||
})
|
||||
|
@ -2,7 +2,7 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
.formulate-input {
|
||||
margin-bottom: 2em;
|
||||
margin-bottom: 1.5em;
|
||||
|
||||
.formulate-input-label {
|
||||
display: block;
|
||||
|
Loading…
Reference in New Issue
Block a user