1
0
mirror of synced 2024-11-24 22:36:02 +03:00

Adds support for new named form methods

This commit is contained in:
Justin Schroeder 2020-05-15 23:20:29 -04:00
parent 1d869936c8
commit 2d097fadb4
12 changed files with 158 additions and 51 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

22
dist/snow.css vendored
View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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.
*/

View File

@ -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

View File

@ -155,10 +155,6 @@ export default {
type: [String, Boolean],
default: false
},
debug: {
type: Boolean,
default: false
},
errors: {
type: [String, Array, Boolean],
default: false

View File

@ -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) => {

View File

@ -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({})
})
})

View File

@ -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',
} })

View File

@ -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);
}