feat: Added possibility to run / reset form validation via $formulario
This commit is contained in:
parent
6612d8a5f9
commit
fd780cd585
@ -7,8 +7,11 @@ import {
|
|||||||
ValidationRuleFn,
|
ValidationRuleFn,
|
||||||
ValidationMessageFn,
|
ValidationMessageFn,
|
||||||
ValidationMessageI18NFn,
|
ValidationMessageI18NFn,
|
||||||
|
ViolationsRecord,
|
||||||
} from '@/validation/validator'
|
} from '@/validation/validator'
|
||||||
|
|
||||||
|
import { FormularioFormInterface } from '@/types'
|
||||||
|
|
||||||
export interface FormularioOptions {
|
export interface FormularioOptions {
|
||||||
validationRules?: Record<string, ValidationRuleFn>;
|
validationRules?: Record<string, ValidationRuleFn>;
|
||||||
validationMessages?: Record<string, ValidationMessageI18NFn|string>;
|
validationMessages?: Record<string, ValidationMessageI18NFn|string>;
|
||||||
@ -21,7 +24,11 @@ export default class Formulario {
|
|||||||
public validationRules: Record<string, ValidationRuleFn> = {}
|
public validationRules: Record<string, ValidationRuleFn> = {}
|
||||||
public validationMessages: Record<string, ValidationMessageI18NFn|string> = {}
|
public validationMessages: Record<string, ValidationMessageI18NFn|string> = {}
|
||||||
|
|
||||||
|
private readonly registry: Map<string, FormularioFormInterface>
|
||||||
|
|
||||||
constructor (options?: FormularioOptions) {
|
constructor (options?: FormularioOptions) {
|
||||||
|
this.registry = new Map()
|
||||||
|
|
||||||
this.validationRules = validationRules
|
this.validationRules = validationRules
|
||||||
this.validationMessages = validationMessages
|
this.validationMessages = validationMessages
|
||||||
|
|
||||||
@ -37,11 +44,54 @@ export default class Formulario {
|
|||||||
this.validationMessages = merge(this.validationMessages, extendWith.validationMessages || {})
|
this.validationMessages = merge(this.validationMessages, extendWith.validationMessages || {})
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
throw new Error(`[Formulario]: Formulario.extend() should be passed an object (was ${typeof extendWith})`)
|
throw new Error(`[Formulario]: Formulario.extend(): should be passed an object (was ${typeof extendWith})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
runValidation (id: string): Promise<ViolationsRecord> {
|
||||||
|
if (!this.registry.has(id)) {
|
||||||
|
throw new Error(`[Formulario]: Formulario.runValidation(): no forms with id "${id}"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = this.registry.get(id) as FormularioFormInterface
|
||||||
|
|
||||||
|
return form.runValidation()
|
||||||
|
}
|
||||||
|
|
||||||
|
resetValidation (id: string): void {
|
||||||
|
if (!this.registry.has(id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = this.registry.get(id) as FormularioFormInterface
|
||||||
|
|
||||||
|
form.resetValidation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by forms instances to add themselves into a registry
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
register (id: string, form: FormularioFormInterface): void {
|
||||||
|
if (this.registry.has(id)) {
|
||||||
|
throw new Error(`[Formulario]: Formulario.register(): id "${id}" is already in use`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.registry.set(id, form)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by forms instances to remove themselves from a registry
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
unregister (id: string): void {
|
||||||
|
if (this.registry.has(id)) {
|
||||||
|
this.registry.delete(id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get validation rules by merging any passed in with global rules.
|
* Get validation rules by merging any passed in with global rules.
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
getRules (extendWith: Record<string, ValidationRuleFn> = {}): Record<string, ValidationRuleFn> {
|
getRules (extendWith: Record<string, ValidationRuleFn> = {}): Record<string, ValidationRuleFn> {
|
||||||
return merge(this.validationRules, extendWith)
|
return merge(this.validationRules, extendWith)
|
||||||
@ -49,6 +99,7 @@ export default class Formulario {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get validation messages by merging any passed in with global messages.
|
* Get validation messages by merging any passed in with global messages.
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
getMessages (vm: Vue, extendWith: Record<string, ValidationMessageI18NFn|string>): Record<string, ValidationMessageFn> {
|
getMessages (vm: Vue, extendWith: Record<string, ValidationMessageI18NFn|string>): Record<string, ValidationMessageFn> {
|
||||||
const raw = merge(this.validationMessages || {}, extendWith)
|
const raw = merge(this.validationMessages || {}, extendWith)
|
||||||
|
@ -25,7 +25,10 @@ import {
|
|||||||
import PathRegistry from '@/PathRegistry'
|
import PathRegistry from '@/PathRegistry'
|
||||||
|
|
||||||
import { FormularioFieldInterface } from '@/types'
|
import { FormularioFieldInterface } from '@/types'
|
||||||
import { Violation } from '@/validation/validator'
|
import {
|
||||||
|
Violation,
|
||||||
|
ViolationsRecord,
|
||||||
|
} from '@/validation/validator'
|
||||||
|
|
||||||
type ErrorsRecord = Record<string, string[]>
|
type ErrorsRecord = Record<string, string[]>
|
||||||
|
|
||||||
@ -34,22 +37,23 @@ type ValidationEventPayload = {
|
|||||||
violations: Violation[];
|
violations: Violation[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type ViolationsRecord = Record<string, Violation[]>
|
let counter = 0
|
||||||
|
|
||||||
@Component({ name: 'FormularioForm' })
|
@Component({ name: 'FormularioForm' })
|
||||||
export default class FormularioForm extends Vue {
|
export default class FormularioForm extends Vue {
|
||||||
@Model('input', { default: () => ({}) })
|
@Model('input', { default: () => ({}) })
|
||||||
public readonly state!: Record<string, unknown>
|
public readonly state!: Record<string, unknown>
|
||||||
|
|
||||||
|
@Prop({ default: () => `formulario-form-${++counter}` })
|
||||||
|
public readonly id!: string
|
||||||
|
|
||||||
// Describes validation errors of whole form
|
// Describes validation errors of whole form
|
||||||
@Prop({ default: () => ({}) }) readonly fieldsErrors!: ErrorsRecord
|
@Prop({ default: () => ({}) }) readonly fieldsErrors!: ErrorsRecord
|
||||||
// Only used on FormularioForm default slot
|
// Only used on FormularioForm default slot
|
||||||
@Prop({ default: () => ([]) }) readonly formErrors!: string[]
|
@Prop({ default: () => ([]) }) readonly formErrors!: string[]
|
||||||
|
|
||||||
public proxy: Record<string, unknown> = {}
|
private proxy: Record<string, unknown> = {}
|
||||||
|
|
||||||
private registry: PathRegistry<FormularioFieldInterface> = new PathRegistry()
|
private registry: PathRegistry<FormularioFieldInterface> = new PathRegistry()
|
||||||
|
|
||||||
// Local error messages are temporal, they wiped each resetValidation call
|
// Local error messages are temporal, they wiped each resetValidation call
|
||||||
private localFieldsErrors: ErrorsRecord = {}
|
private localFieldsErrors: ErrorsRecord = {}
|
||||||
private localFormErrors: string[] = []
|
private localFormErrors: string[] = []
|
||||||
@ -148,6 +152,11 @@ export default class FormularioForm extends Vue {
|
|||||||
|
|
||||||
public created (): void {
|
public created (): void {
|
||||||
this.syncProxy()
|
this.syncProxy()
|
||||||
|
this.$formulario.register(this.id, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public beforeDestroy (): void {
|
||||||
|
this.$formulario.unregister(this.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
public runValidation (): Promise<ViolationsRecord> {
|
public runValidation (): Promise<ViolationsRecord> {
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { Violation } from '@/validation/validator'
|
import { Violation, ViolationsRecord } from '@/validation/validator'
|
||||||
|
|
||||||
|
export interface FormularioFormInterface {
|
||||||
|
runValidation(): Promise<ViolationsRecord>;
|
||||||
|
resetValidation(): void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FormularioFieldInterface {
|
export interface FormularioFieldInterface {
|
||||||
hasModel: boolean;
|
hasModel: boolean;
|
||||||
|
@ -11,6 +11,8 @@ export interface Violation {
|
|||||||
context: ValidationContext|null;
|
context: ValidationContext|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ViolationsRecord = Record<string, Violation[]>
|
||||||
|
|
||||||
export interface ValidationRuleFn {
|
export interface ValidationRuleFn {
|
||||||
(context: ValidationContext, ...args: any[]): Promise<boolean>|boolean;
|
(context: ValidationContext, ...args: any[]): Promise<boolean>|boolean;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,52 @@ describe('FormularioForm', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('resolves runValidation via $formulario', async () => {
|
||||||
|
const wrapper = mount(FormularioForm, {
|
||||||
|
propsData: {
|
||||||
|
id: 'address',
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
default: `
|
||||||
|
<div>
|
||||||
|
<FormularioField name="address.street" validation="required" />
|
||||||
|
<FormularioField name="address.building" validation="required" />
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const violations = await wrapper.vm.$formulario.runValidation('address')
|
||||||
|
const state = {
|
||||||
|
address: {
|
||||||
|
street: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(violations).toEqual({
|
||||||
|
'address.street': [{
|
||||||
|
message: expect.any(String),
|
||||||
|
rule: 'required',
|
||||||
|
args: [],
|
||||||
|
context: {
|
||||||
|
name: 'address.street',
|
||||||
|
value: null,
|
||||||
|
formValues: state,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
'address.building': [{
|
||||||
|
message: expect.any(String),
|
||||||
|
rule: 'required',
|
||||||
|
args: [],
|
||||||
|
context: {
|
||||||
|
name: 'address.building',
|
||||||
|
value: '',
|
||||||
|
formValues: state,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('resolves hasValidationErrors to true', async () => {
|
test('resolves hasValidationErrors to true', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
slots: {
|
slots: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user