1
0
mirror of synced 2024-11-25 14:56:03 +03:00

feat: Renamed FormularioInput => FormularioField, FormularioGrouping => FormularioFieldGroup, old names are preserved in plugin install method for compatibility

This commit is contained in:
Zaytsev Kirill 2021-05-22 16:50:53 +03:00
parent 6a86d1f7b7
commit 013931fbfc
10 changed files with 95 additions and 87 deletions

View File

@ -5,7 +5,7 @@ for working with forms and gives full control on the form presentation.
## Examples
Every form control have to rendered inside FormularioInput component. This component provides `id` and `context` in
Every form control have to rendered inside FormularioField component. This component provides `id` and `context` in
v-slot props. Control should use `context.model` as v-model and `context.runValidation` as handler for `blur` event
(it is necessary for validation when property `validationBehavior` is `demand`). Errors list for a field can be
accessed through `context.allErrors`.
@ -27,7 +27,7 @@ The example below creates the authorization form from data:
v-model="formData"
name="formName"
>
<FormularioInput
<FormularioField
v-slot="{ context }"
name="username"
validation="required|email"
@ -46,9 +46,9 @@ The example below creates the authorization form from data:
{{ error }}
</span>
</div>
</FormularioInput>
</FormularioField>
<FormularioInput
<FormularioField
v-slot="{ context }"
name="password"
validation="required|min:4,length"
@ -57,10 +57,10 @@ The example below creates the authorization form from data:
v-model="context.model"
type="password"
>
</FormularioInput>
</FormularioField>
<FormularioGrouping name="options">
<FormularioInput
<FormularioFieldGroup name="options">
<FormularioField
v-slot="{ context }"
name="anonymous"
>
@ -72,10 +72,10 @@ The example below creates the authorization form from data:
>
<label for="options-anonymous">As anonymous</label>
</div>
</FormularioInput>
</FormularioGrouping>
</FormularioField>
</FormularioFieldGroup>
<FormularioInput
<FormularioField
v-slot="{ context }"
name="options.tags[0]"
>
@ -83,7 +83,7 @@ The example below creates the authorization form from data:
v-model="context.model"
type="text"
>
</FormularioInput>
</FormularioField>
</FormularioForm>
```

View File

@ -50,8 +50,8 @@ interface ModelSetConverter {
type Empty = null | undefined
@Component({ name: 'FormularioInput', inheritAttrs: false })
export default class FormularioInput extends Vue {
@Component({ name: 'FormularioField', inheritAttrs: false })
export default class FormularioField extends Vue {
@Inject({ default: undefined }) formularioSetter!: Function|undefined
@Inject({ default: () => (): void => {} }) onFormularioFieldValidation!: Function
@Inject({ default: undefined }) formularioRegister!: Function|undefined

View File

@ -13,8 +13,8 @@ import {
Provide,
} from 'vue-property-decorator'
@Component({ name: 'FormularioGrouping' })
export default class FormularioGrouping extends Vue {
@Component({ name: 'FormularioFieldGroup' })
export default class FormularioFieldGroup extends Vue {
@Inject({ default: '' }) path!: string
@Prop({ required: true })

View File

@ -9,7 +9,7 @@ import Vue from 'vue'
import { Component, Model, Prop, Provide, Watch } from 'vue-property-decorator'
import { clone, getNested, has, merge, setNested, shallowEqualObjects } from '@/utils'
import Registry from '@/form/registry'
import FormularioInput from '@/FormularioInput.vue'
import FormularioField from '@/FormularioField.vue'
import {
ErrorHandler,
@ -125,7 +125,7 @@ export default class FormularioForm extends Vue {
}
@Provide('formularioRegister')
register (field: string, component: FormularioInput): void {
register (field: string, component: FormularioField): void {
this.registry.add(field, component)
}
@ -149,7 +149,7 @@ export default class FormularioForm extends Vue {
}
this.registry.getNested(field).forEach((registryField, registryKey) => {
const $input = this.registry.get(registryKey) as FormularioInput
const $input = this.registry.get(registryKey) as FormularioField
const oldValue = getNested(this.proxy, registryKey)
const newValue = getNested(values, registryKey)
@ -193,8 +193,8 @@ export default class FormularioForm extends Vue {
}
hasValidationErrors (): Promise<boolean> {
return Promise.all(this.registry.reduce((resolvers: Promise<boolean>[], input: FormularioInput) => {
resolvers.push(input.runValidation() && input.hasValidationErrors())
return Promise.all(this.registry.reduce((resolvers: Promise<boolean>[], field: FormularioField) => {
resolvers.push(field.runValidation() && field.hasValidationErrors())
return resolvers
}, [])).then(results => results.some(hasErrors => hasErrors))
}
@ -202,8 +202,8 @@ export default class FormularioForm extends Vue {
resetValidation (): void {
this.localFormErrors = []
this.localFieldErrors = {}
this.registry.forEach((input: FormularioInput) => {
input.resetValidation()
this.registry.forEach((field: FormularioField) => {
field.resetValidation()
})
}
}

View File

@ -1,6 +1,6 @@
import { shallowEqualObjects, has, getNested } from '@/utils'
import FormularioField from '@/FormularioField.vue'
import FormularioForm from '@/FormularioForm.vue'
import FormularioInput from '@/FormularioInput.vue'
/**
* Component registry with inherent depth to handle complex nesting. This is
@ -8,7 +8,7 @@ import FormularioInput from '@/FormularioInput.vue'
*/
export default class Registry {
private ctx: FormularioForm
private registry: Map<string, FormularioInput>
private registry: Map<string, FormularioField>
/**
* Create a new registry of components.
@ -24,7 +24,7 @@ export default class Registry {
* @param {string} field name of the field.
* @param {FormularioForm} component the actual component instance.
*/
add (field: string, component: FormularioInput): void {
add (field: string, component: FormularioField): void {
if (this.registry.has(field)) {
return
}
@ -85,14 +85,14 @@ export default class Registry {
/**
* Get a particular registry value.
*/
get (key: string): FormularioInput | undefined {
get (key: string): FormularioField | undefined {
return this.registry.get(key)
}
/**
* Get registry value for key or nested to given key
*/
getNested (key: string): Map<string, FormularioInput> {
getNested (key: string): Map<string, FormularioField> {
const result = new Map()
for (const i of this.registry.keys()) {

View File

@ -1,14 +1,21 @@
import Formulario, { FormularioOptions } from '@/Formulario.ts'
import { VueConstructor } from 'vue'
import Formulario, { FormularioOptions } from '@/Formulario.ts'
import FormularioField from '@/FormularioField.vue'
import FormularioFieldGroup from '@/FormularioFieldGroup.vue'
import FormularioForm from '@/FormularioForm.vue'
import FormularioGrouping from '@/FormularioGrouping.vue'
import FormularioInput from '@/FormularioInput.vue'
export default {
install (Vue: VueConstructor, options?: FormularioOptions): void {
Vue.component('FormularioField', FormularioField)
Vue.component('FormularioFieldGroup', FormularioFieldGroup)
Vue.component('FormularioForm', FormularioForm)
Vue.component('FormularioGrouping', FormularioGrouping)
Vue.component('FormularioInput', FormularioInput)
// @deprecated Use FormularioField instead
Vue.component('FormularioInput', FormularioField)
// @deprecated Use FormularioFieldGroup instead
Vue.component('FormularioGrouping', FormularioFieldGroup)
Vue.mixin({
beforeCreate () {

View File

@ -6,7 +6,7 @@ export interface ErrorHandler {
export interface ErrorObserver {
callback: ErrorHandler;
type: 'form' | 'input';
type: 'form' | 'field';
field?: string;
}

View File

@ -2,19 +2,19 @@
<FormularioForm v-model="values">
<h1>Address list</h1>
<FormularioInput
<FormularioField
v-slot="addressList"
name="addressList"
>
<FormularioGrouping name="addressList">
<FormularioGrouping
<FormularioFieldGroup name="addressList">
<FormularioFieldGroup
v-for="(address, addressIndex) in addressList.context.model"
:key="'address-' + addressIndex"
:name="addressIndex"
:is-array-item="true"
class="row mx-n2"
>
<FormularioInput
<FormularioField
v-slot="{ context }"
class="col col-auto px-2 mb-3"
name="street"
@ -36,9 +36,9 @@
>
{{ error }}
</div>
</FormularioInput>
</FormularioField>
<FormularioInput
<FormularioField
v-slot="{ context }"
class="col col-auto px-2 mb-3"
name="building"
@ -60,7 +60,7 @@
>
{{ error }}
</div>
</FormularioInput>
</FormularioField>
<div class="remove-btn-wrapper">
<button
@ -71,8 +71,8 @@
Remove
</button>
</div>
</FormularioGrouping>
</FormularioGrouping>
</FormularioFieldGroup>
</FormularioFieldGroup>
<button
class="btn btn-primary"
@ -81,22 +81,22 @@
>
Add address
</button>
</FormularioInput>
</FormularioField>
</FormularioForm>
</template>
<script>
import FormularioField from '@/FormularioField'
import FormularioFieldGroup from '@/FormularioFieldGroup'
import FormularioForm from '@/FormularioForm'
import FormularioGrouping from '@/FormularioGrouping'
import FormularioInput from '@/FormularioInput'
export default {
name: 'ExampleAddressListTale',
components: {
FormularioField,
FormularioForm,
FormularioGrouping,
FormularioInput,
FormularioFieldGroup,
},
data: () => ({

View File

@ -4,7 +4,7 @@ import { mount } from '@vue/test-utils'
import Formulario from '@/index.ts'
import FormularioForm from '@/FormularioForm.vue'
import FormularioInput from '@/FormularioInput.vue'
import FormularioField from '@/FormularioField.vue'
const globalRule = jest.fn(() => false)
@ -18,9 +18,9 @@ Vue.use(Formulario, {
},
})
describe('FormularioInput', () => {
describe('FormularioField', () => {
it('Allows custom field-rule level validation strings', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
value: 'other value',
@ -37,7 +37,7 @@ describe('FormularioInput', () => {
})
it('No validation on created when validationBehavior is not live', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|in:abcdef',
@ -53,7 +53,7 @@ describe('FormularioInput', () => {
})
it('No validation on value change when validationBehavior is "submit"', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|in:abcdef',
@ -83,7 +83,7 @@ describe('FormularioInput', () => {
})
it('Allows custom field-rule level validation functions', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|in:abcdef',
@ -100,7 +100,7 @@ describe('FormularioInput', () => {
})
it('No validation on created when validationBehavior is default', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|in:abcdef',
@ -116,7 +116,7 @@ describe('FormularioInput', () => {
})
it('Uses custom async validation rules on defined on the field', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|foobar',
@ -134,7 +134,7 @@ describe('FormularioInput', () => {
})
it('Uses custom sync validation rules on defined on the field', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
value: 'bar',
@ -152,7 +152,7 @@ describe('FormularioInput', () => {
})
it('Uses global custom validation rules', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
value: 'bar',
@ -165,7 +165,7 @@ describe('FormularioInput', () => {
})
it('Emits correct validation event', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'fieldName',
value: '',
@ -188,7 +188,7 @@ describe('FormularioInput', () => {
})
it('Can bail on validation when encountering the bail rule', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'bail|required|in:xyz',
@ -200,7 +200,7 @@ describe('FormularioInput', () => {
})
it('Can show multiple validation errors if they occur before the bail rule', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|in:xyz|bail',
@ -212,7 +212,7 @@ describe('FormularioInput', () => {
})
it('Can avoid bail behavior by using modifier', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
value: '123',
@ -225,7 +225,7 @@ describe('FormularioInput', () => {
})
it('Prevents later error messages when modified rule fails', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: '^required|in:xyz|min:10,length',
@ -237,7 +237,7 @@ describe('FormularioInput', () => {
})
it('can bail in the middle of the rule set with a modifier', async () => {
const wrapper = mount(FormularioInput, {
const wrapper = mount(FormularioField, {
propsData: {
name: 'test',
validation: 'required|^in:xyz|min:10,length',
@ -253,14 +253,14 @@ describe('FormularioInput', () => {
propsData: { name: 'test' },
slots: {
default: `
<FormularioInput
<FormularioField
v-slot="{ context }"
name="testinput"
validation="required"
validation-behavior="submit"
>
<span v-for="error in context.violations">{{ error.message }}</span>
</FormularioInput>
</FormularioField>
`
}
})
@ -281,9 +281,9 @@ describe('FormularioInput', () => {
data: () => ({ values: { test: 'abcd' } }),
template: `
<FormularioForm v-model="values">
<FormularioInput v-slot="{ context }" :model-get-converter="onGet" name="test" >
<FormularioField v-slot="{ context }" :model-get-converter="onGet" name="test" >
<span>{{ context.model }}</span>
</FormularioInput>
</FormularioField>
</FormularioForm>
`,
methods: {
@ -310,9 +310,9 @@ describe('FormularioInput', () => {
data: () => ({ values: { test: 'abcd' } }),
template: `
<FormularioForm v-model="values">
<FormularioInput v-slot="{ context }" :model-get-converter="onGet" :model-set-converter="onSet" name="test" >
<FormularioField v-slot="{ context }" :model-get-converter="onGet" :model-set-converter="onSet" name="test" >
<input type="text" v-model="context.model">
</FormularioInput>
</FormularioField>
</FormularioForm>
`,
methods: {

View File

@ -1,22 +1,24 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import Formulario from '@/index.ts'
import FormularioFieldGroup from '@/FormularioFieldGroup.vue'
import FormularioForm from '@/FormularioForm.vue'
import FormularioGrouping from '@/FormularioGrouping.vue'
Vue.use(Formulario)
describe('FormularioGrouping', () => {
describe('FormularioFieldGroup', () => {
it('Grouped fields to be set', async () => {
const wrapper = mount(FormularioForm, {
slots: {
default: `
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<FormularioFieldGroup name="group">
<FormularioField name="text" v-slot="{ context }">
<input type="text" v-model="context.model">
</FormularioInput>
</FormularioGrouping>
</FormularioField>
</FormularioFieldGroup>
`
}
})
@ -31,8 +33,7 @@ describe('FormularioGrouping', () => {
const emitted = wrapper.emitted()
expect(emitted['submit']).toBeTruthy()
expect(emitted['submit'].length).toBe(1)
expect(emitted['submit'][0]).toEqual([{ group: { text: 'test' } }])
expect(emitted['submit']).toEqual([[{ group: { text: 'test' } }]])
})
it('Grouped fields to be got', async () => {
@ -45,11 +46,11 @@ describe('FormularioGrouping', () => {
},
slots: {
default: `
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<FormularioFieldGroup name="group">
<FormularioField name="text" v-slot="{ context }">
<input type="text" v-model="context.model">
</FormularioInput>
</FormularioGrouping>
</FormularioField>
</FormularioFieldGroup>
`
}
})
@ -61,12 +62,12 @@ describe('FormularioGrouping', () => {
data: () => ({ values: {} }),
template: `
<FormularioForm name="form" v-model="values">
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<FormularioFieldGroup name="group">
<FormularioField name="text" v-slot="{ context }">
<input type="text" v-model="context.model">
<span>{{ values.group.text }}</span>
</FormularioInput>
</FormularioGrouping>
</FormularioField>
</FormularioFieldGroup>
</FormularioForm>
`
})
@ -85,9 +86,9 @@ describe('FormularioGrouping', () => {
slots: {
default: `
<FormularioGrouping name="group">
<FormularioInput ref="input" name="text" v-slot="{ context }">
<FormularioField ref="input" name="text" v-slot="{ context }">
<span v-for="error in context.errors">{{ error }}</span>
</FormularioInput>
</FormularioField>
</FormularioGrouping>
`,
},