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,
|
||||
ValidationMessageFn,
|
||||
ValidationMessageI18NFn,
|
||||
ViolationsRecord,
|
||||
} from '@/validation/validator'
|
||||
|
||||
import { FormularioFormInterface } from '@/types'
|
||||
|
||||
export interface FormularioOptions {
|
||||
validationRules?: Record<string, ValidationRuleFn>;
|
||||
validationMessages?: Record<string, ValidationMessageI18NFn|string>;
|
||||
@ -21,7 +24,11 @@ export default class Formulario {
|
||||
public validationRules: Record<string, ValidationRuleFn> = {}
|
||||
public validationMessages: Record<string, ValidationMessageI18NFn|string> = {}
|
||||
|
||||
private readonly registry: Map<string, FormularioFormInterface>
|
||||
|
||||
constructor (options?: FormularioOptions) {
|
||||
this.registry = new Map()
|
||||
|
||||
this.validationRules = validationRules
|
||||
this.validationMessages = validationMessages
|
||||
|
||||
@ -37,11 +44,54 @@ export default class Formulario {
|
||||
this.validationMessages = merge(this.validationMessages, extendWith.validationMessages || {})
|
||||
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.
|
||||
* @internal
|
||||
*/
|
||||
getRules (extendWith: Record<string, ValidationRuleFn> = {}): Record<string, ValidationRuleFn> {
|
||||
return merge(this.validationRules, extendWith)
|
||||
@ -49,6 +99,7 @@ export default class Formulario {
|
||||
|
||||
/**
|
||||
* Get validation messages by merging any passed in with global messages.
|
||||
* @internal
|
||||
*/
|
||||
getMessages (vm: Vue, extendWith: Record<string, ValidationMessageI18NFn|string>): Record<string, ValidationMessageFn> {
|
||||
const raw = merge(this.validationMessages || {}, extendWith)
|
||||
|
@ -25,7 +25,10 @@ import {
|
||||
import PathRegistry from '@/PathRegistry'
|
||||
|
||||
import { FormularioFieldInterface } from '@/types'
|
||||
import { Violation } from '@/validation/validator'
|
||||
import {
|
||||
Violation,
|
||||
ViolationsRecord,
|
||||
} from '@/validation/validator'
|
||||
|
||||
type ErrorsRecord = Record<string, string[]>
|
||||
|
||||
@ -34,22 +37,23 @@ type ValidationEventPayload = {
|
||||
violations: Violation[];
|
||||
}
|
||||
|
||||
type ViolationsRecord = Record<string, Violation[]>
|
||||
let counter = 0
|
||||
|
||||
@Component({ name: 'FormularioForm' })
|
||||
export default class FormularioForm extends Vue {
|
||||
@Model('input', { default: () => ({}) })
|
||||
public readonly state!: Record<string, unknown>
|
||||
|
||||
@Prop({ default: () => `formulario-form-${++counter}` })
|
||||
public readonly id!: string
|
||||
|
||||
// Describes validation errors of whole form
|
||||
@Prop({ default: () => ({}) }) readonly fieldsErrors!: ErrorsRecord
|
||||
// Only used on FormularioForm default slot
|
||||
@Prop({ default: () => ([]) }) readonly formErrors!: string[]
|
||||
|
||||
public proxy: Record<string, unknown> = {}
|
||||
|
||||
private proxy: Record<string, unknown> = {}
|
||||
private registry: PathRegistry<FormularioFieldInterface> = new PathRegistry()
|
||||
|
||||
// Local error messages are temporal, they wiped each resetValidation call
|
||||
private localFieldsErrors: ErrorsRecord = {}
|
||||
private localFormErrors: string[] = []
|
||||
@ -148,6 +152,11 @@ export default class FormularioForm extends Vue {
|
||||
|
||||
public created (): void {
|
||||
this.syncProxy()
|
||||
this.$formulario.register(this.id, this)
|
||||
}
|
||||
|
||||
public beforeDestroy (): void {
|
||||
this.$formulario.unregister(this.id)
|
||||
}
|
||||
|
||||
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 {
|
||||
hasModel: boolean;
|
||||
|
@ -11,6 +11,8 @@ export interface Violation {
|
||||
context: ValidationContext|null;
|
||||
}
|
||||
|
||||
export type ViolationsRecord = Record<string, Violation[]>
|
||||
|
||||
export interface ValidationRuleFn {
|
||||
(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 () => {
|
||||
const wrapper = mount(FormularioForm, {
|
||||
slots: {
|
||||
|
Loading…
Reference in New Issue
Block a user