Skip to content

Commit

Permalink
fix(vuelidate#1232): clear $externalResults on $model change after ru…
Browse files Browse the repository at this point in the history
…les recompute

If you're using dynamic rules object via computed as documented, your client-side
validations work dynamically as expected. If you add $externalResults to the mix and
the rules rules are re-computed after $externalErrors been applied, $
externalErrors are no longer cleared when $model changes.

https://stackblitz.com/edit/vitejs-vite-j6ywfz?file=src%2FAppForm.vue
  • Loading branch information
renatodeleao committed Mar 12, 2024
1 parent 08aa514 commit 6bb073d
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
3 changes: 2 additions & 1 deletion packages/vuelidate/src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,8 @@ export function setValidations ({
const s = unwrap(state)
const external = unwrap(externalResults)
if (external) {
external[key] = cachedExternalResults[key]
// delete external[key] breaks vue:2 specs
external[key] = undefined
}
if (isRef(s[key])) {
s[key].value = val
Expand Down
54 changes: 54 additions & 0 deletions packages/vuelidate/test/unit/specs/validation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,60 @@ describe('useVuelidate', () => {
expect(vm.v.number.$error).toBe(false)
expect(vm.v.number.$silentErrors).toEqual([])
})

// https://github.com/vuelidate/vuelidate/issues/1232
it('when dynamic rules is used, it still automatically clears $externalResults on $model change', async () => {
const state = reactive({
field: 0,
validateWithIsEven: true
})
const dynamicRules = computed(() => {
return state.validateWithIsEven
? { field: { isEven } }
: { field: { placebo: () => true } }
})
const $externalResults = ref({})
const { vm } = await createSimpleWrapper(dynamicRules, state, { $externalResults })

const externalErrorObject = {
$message: message,
$params: {},
$pending: false,
$property: 'field',
$propertyPath: 'field',
$response: null,
$uid: 'field-externalResult-0',
$validator: '$externalResults'
}
// assert the initial state
state.validateWithIsEven = true
vm.v.field.$model = 5
expect(vm.v.field.$invalid).toBe(true)

// recompute rules, assert validations updated
state.validateWithIsEven = false
await vm.$nextTick()
expect(vm.v.field.$invalid).toBe(false)

// NOW TO THE ISSUE

vm.v.field.$model = 2
$externalResults.value = { field: message }
expect(vm.v.field.$error).toBe(true)
expect(vm.v.field.$errors).toEqual([externalErrorObject])

// trigger recomputation of rules while $externalResults are applied,
// this is the key, because when $model setter is called cachedExternalResults
// now exists and has previous entry for the field path setting external
// instead of removing it
state.validateWithIsEven = true
await vm.$nextTick()

// change $model, ensure $externalResults are cleared
// before the fix, this spec would fail
vm.v.field.$model = 4
expect(vm.v.field.$errors).toEqual([])
})
})

describe('$rewardEarly', () => {
Expand Down

0 comments on commit 6bb073d

Please sign in to comment.