feat: Renamed FormularioInput => FormularioField, FormularioGrouping => FormularioFieldGroup, old names are preserved in plugin install method for compatibility
This commit is contained in:
parent
6a86d1f7b7
commit
013931fbfc
22
README.md
22
README.md
@ -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>
|
||||
```
|
||||
|
||||
|
@ -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
|
@ -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 })
|
@ -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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
17
src/index.ts
17
src/index.ts
@ -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 () {
|
||||
|
@ -6,7 +6,7 @@ export interface ErrorHandler {
|
||||
|
||||
export interface ErrorObserver {
|
||||
callback: ErrorHandler;
|
||||
type: 'form' | 'input';
|
||||
type: 'form' | 'field';
|
||||
field?: string;
|
||||
}
|
||||
|
||||
|
@ -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: () => ({
|
||||
|
@ -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: {
|
@ -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>
|
||||
`,
|
||||
},
|
Loading…
Reference in New Issue
Block a user