Adds support for new named form methods
This commit is contained in:
parent
1d869936c8
commit
2d097fadb4
2
dist/formulate.esm.js
vendored
2
dist/formulate.esm.js
vendored
File diff suppressed because one or more lines are too long
4
dist/formulate.min.js
vendored
4
dist/formulate.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/formulate.umd.js
vendored
2
dist/formulate.umd.js
vendored
File diff suppressed because one or more lines are too long
22
dist/snow.css
vendored
22
dist/snow.css
vendored
@ -330,22 +330,22 @@
|
||||
.formulate-input[data-classification='group'] [data-is-repeatable] .formulate-input-group-repeatable-remove {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: calc(50% - .75em);
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
top: calc(50% - .65em + .5em);
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
background-color: #cecece;
|
||||
right: .75em;
|
||||
border-radius: 1.5em;
|
||||
right: .85em;
|
||||
border-radius: 1.3em;
|
||||
cursor: pointer;
|
||||
transition: background-color .2s; }
|
||||
.formulate-input[data-classification='group'] [data-is-repeatable] .formulate-input-group-repeatable-remove::before, .formulate-input[data-classification='group'] [data-is-repeatable] .formulate-input-group-repeatable-remove::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: calc(50% - .125em);
|
||||
left: 0.375em;
|
||||
top: calc(50% - .1em);
|
||||
left: .325em;
|
||||
display: block;
|
||||
width: .75em;
|
||||
height: .25em;
|
||||
width: .65em;
|
||||
height: .2em;
|
||||
background-color: white;
|
||||
transform-origin: center center;
|
||||
transition: transform .25s; }
|
||||
@ -354,8 +354,8 @@
|
||||
background-color: #dc2c2c; }
|
||||
.formulate-input[data-classification='group'] [data-is-repeatable] .formulate-input-group-repeatable-remove:hover::after, .formulate-input[data-classification='group'] [data-is-repeatable] .formulate-input-group-repeatable-remove:hover::before {
|
||||
height: .2em;
|
||||
width: .9em;
|
||||
left: .3em;
|
||||
width: .75em;
|
||||
left: .25em;
|
||||
top: calc(50% - .075em); }
|
||||
.formulate-input[data-classification='group'] [data-is-repeatable] .formulate-input-group-repeatable-remove:hover::after {
|
||||
transform: rotate(45deg); }
|
||||
|
2
dist/snow.min.css
vendored
2
dist/snow.min.css
vendored
File diff suppressed because one or more lines are too long
@ -103,10 +103,10 @@ class Formulate {
|
||||
* implementation is open to community review.
|
||||
*/
|
||||
nextId (vm) {
|
||||
const path = vm.$route && vm.$route.path || false
|
||||
const pathPrefix = path ? vm.$route.path.replace(/[\/\\.\s]/g, '-') : 'global';
|
||||
const path = vm.$route && vm.$route.path ? vm.$route.path : false
|
||||
const pathPrefix = path ? vm.$route.path.replace(/[/\\.\s]/g, '-') : 'global'
|
||||
if (!Object.prototype.hasOwnProperty.call(this.idRegistry, pathPrefix)) {
|
||||
this.idRegistry[pathPrefix] = 0;
|
||||
this.idRegistry[pathPrefix] = 0
|
||||
}
|
||||
return `${this.options.idPrefix}${pathPrefix}-${++this.idRegistry[pathPrefix]}`
|
||||
}
|
||||
@ -183,7 +183,7 @@ class Formulate {
|
||||
*/
|
||||
slotComponent (type, slot) {
|
||||
const def = this.options.library[type]
|
||||
if (def.slotComponents && def.slotComponents[slot]) {
|
||||
if (def && def.slotComponents && def.slotComponents[slot]) {
|
||||
return def.slotComponents[slot]
|
||||
}
|
||||
return this.options.slotComponents[slot]
|
||||
@ -297,6 +297,39 @@ class Formulate {
|
||||
return e
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a form.
|
||||
* @param {string} formName
|
||||
* @param {object} initialValue
|
||||
*/
|
||||
reset (formName, initialValue = {}) {
|
||||
this.resetValidation(formName)
|
||||
this.setValues(formName, initialValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the form's validation messages.
|
||||
* @param {string} formName
|
||||
*/
|
||||
resetValidation (formName) {
|
||||
const form = this.registry.get(formName)
|
||||
form.hideErrors(formName)
|
||||
form.namedErrors = []
|
||||
form.namedFieldErrors = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the form values.
|
||||
* @param {string} formName
|
||||
* @param {object} values
|
||||
*/
|
||||
setValues (formName, values) {
|
||||
if (values && !Array.isArray(values) && typeof values === 'object') {
|
||||
const form = this.registry.get(formName)
|
||||
form.setValues({ ...values })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file uploader.
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { shallowEqualObjects, arrayify, has } from './libs/utils'
|
||||
import { arrayify, has } from './libs/utils'
|
||||
import useRegistry, { useRegistryComputed, useRegistryMethods, useRegistryProviders } from './libs/registry'
|
||||
import FormSubmission from './FormSubmission'
|
||||
|
||||
@ -96,20 +96,12 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
formulateValue: {
|
||||
handler (newValue, oldValue) {
|
||||
handler (values) {
|
||||
if (this.isVmodeled &&
|
||||
newValue &&
|
||||
typeof newValue === 'object'
|
||||
values &&
|
||||
typeof values === 'object'
|
||||
) {
|
||||
for (const field in newValue) {
|
||||
if (this.registry.has(field) &&
|
||||
!shallowEqualObjects(newValue[field], this.proxy[field]) &&
|
||||
!shallowEqualObjects(newValue[field], this.registry.get(field).proxy[field])
|
||||
) {
|
||||
this.setFieldValue(field, newValue[field])
|
||||
this.registry.get(field).context.model = newValue[field]
|
||||
}
|
||||
}
|
||||
this.setValues(values)
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
|
@ -155,10 +155,6 @@ export default {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
debug: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errors: {
|
||||
type: [String, Array, Boolean],
|
||||
default: false
|
||||
|
@ -187,7 +187,12 @@ export function useRegistryMethods (without = []) {
|
||||
}
|
||||
},
|
||||
setFieldValue (field, value) {
|
||||
Object.assign(this.proxy, { [field]: value })
|
||||
if (value === undefined) {
|
||||
const { [field]: value, ...proxy } = this.proxy
|
||||
this.proxy = proxy
|
||||
} else {
|
||||
Object.assign(this.proxy, { [field]: value })
|
||||
}
|
||||
this.$emit('input', Object.assign({}, this.proxy))
|
||||
},
|
||||
getFormValues () {
|
||||
@ -204,6 +209,26 @@ export function useRegistryMethods (without = []) {
|
||||
this.registry.map(input => {
|
||||
input.formShouldShowErrors = true
|
||||
})
|
||||
},
|
||||
hideErrors () {
|
||||
this.childrenShouldShowErrors = false
|
||||
this.registry.map(input => {
|
||||
input.formShouldShowErrors = false
|
||||
input.behavioralErrorVisibility = false
|
||||
})
|
||||
},
|
||||
setValues (values) {
|
||||
// Collect all keys, existing and incoming
|
||||
const keys = Array.from(new Set(Object.keys(values).concat(Object.keys(this.proxy))))
|
||||
keys.forEach(field => {
|
||||
if (this.registry.has(field) &&
|
||||
!shallowEqualObjects(values[field], this.proxy[field]) &&
|
||||
!shallowEqualObjects(values[field], this.registry.get(field).proxy)
|
||||
) {
|
||||
this.setFieldValue(field, values[field])
|
||||
this.registry.get(field).context.model = values[field]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return Object.keys(methods).reduce((withMethods, key) => {
|
||||
|
@ -536,4 +536,65 @@ describe('FormulateForm', () => {
|
||||
expect(wrapper.findComponent(FormulateForm).vm.proxy).toEqual({ foo: 'bar' })
|
||||
expect(wrapper.vm.formData).toEqual({ foo: 'bar' })
|
||||
})
|
||||
|
||||
it('it allows the removal of properties in proxy.', async () => {
|
||||
const wrapper = mount({
|
||||
template: `
|
||||
<FormulateForm
|
||||
v-model="formData"
|
||||
name="login"
|
||||
ref="form"
|
||||
>
|
||||
<FormulateInput type="text" name="username" validation="required" v-model="username" />
|
||||
<FormulateInput type="password" name="password" validation="required|min:4,length" />
|
||||
</FormulateForm>
|
||||
`,
|
||||
data () {
|
||||
return {
|
||||
formData: {},
|
||||
username: undefined
|
||||
}
|
||||
}
|
||||
})
|
||||
wrapper.find('input[type="text"]').setValue('foo')
|
||||
await flushPromises()
|
||||
expect(wrapper.vm.username).toEqual('foo')
|
||||
expect(wrapper.vm.formData).toEqual({ username: 'foo' })
|
||||
wrapper.vm.$refs.form.setValues({})
|
||||
await flushPromises()
|
||||
expect(wrapper.vm.formData).toEqual({ username: '' })
|
||||
})
|
||||
|
||||
it('it allows resetting a form, hiding validation and clearing inputs.', async () => {
|
||||
const wrapper = mount({
|
||||
template: `
|
||||
<FormulateForm
|
||||
v-model="formData"
|
||||
name="login"
|
||||
>
|
||||
<FormulateInput type="text" name="username" validation="required" />
|
||||
<FormulateInput type="password" name="password" validation="required|min:4,length" />
|
||||
</FormulateForm>
|
||||
`,
|
||||
data () {
|
||||
return {
|
||||
formData: {}
|
||||
}
|
||||
}
|
||||
})
|
||||
const password = wrapper.find('input[type="password"]')
|
||||
password.setValue('foo')
|
||||
password.trigger('blur')
|
||||
wrapper.find('form').trigger('submit')
|
||||
wrapper.vm.$formulate.handle({
|
||||
inputErrors: { username: ['Failed'] }
|
||||
}, 'login')
|
||||
await flushPromises()
|
||||
// First make sure we showed the errors
|
||||
expect(wrapper.findAll('.formulate-input-error').length).toBe(3)
|
||||
wrapper.vm.$formulate.reset('login')
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('.formulate-input-error').length).toBe(0)
|
||||
expect(wrapper.vm.formData).toEqual({})
|
||||
})
|
||||
})
|
||||
|
@ -294,9 +294,9 @@ describe('FormulateInput', () => {
|
||||
expect(wrapper.vm.context.visibleValidationErrors.length).toBe(2);
|
||||
})
|
||||
|
||||
it('doesnt show errors on blur when set error-behavior is submit', async () => {
|
||||
it('does not show errors on blur when set error-behavior is submit', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'special',
|
||||
type: 'text',
|
||||
validation: 'required',
|
||||
errorBehavior: 'submit',
|
||||
} })
|
||||
|
@ -413,12 +413,12 @@
|
||||
&-remove {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: calc(50% - .75em);
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
top: calc(50% - .65em + .5em);
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
background-color: $formulate-gray-d;
|
||||
right: .75em;
|
||||
border-radius: 1.5em;
|
||||
right: .85em;
|
||||
border-radius: 1.3em;
|
||||
cursor: pointer;
|
||||
transition: background-color .2s;
|
||||
|
||||
@ -426,11 +426,11 @@
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: calc(50% - .125em);
|
||||
left: 0.375em;
|
||||
top: calc(50% - .1em);
|
||||
left: .325em;
|
||||
display: block;
|
||||
width: .75em;
|
||||
height: .25em;
|
||||
width: .65em;
|
||||
height: .2em;
|
||||
background-color: white;
|
||||
transform-origin: center center;
|
||||
transition: transform .25s;
|
||||
@ -443,8 +443,8 @@
|
||||
&::after,
|
||||
&::before {
|
||||
height: .2em;
|
||||
width: .9em;
|
||||
left: .3em;
|
||||
width: .75em;
|
||||
left: .25em;
|
||||
top: calc(50% - .075em);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user