forked from vuelidate/vuelidate
/
index.js
121 lines (108 loc) · 4.6 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { watch, computed, getCurrentInstance, onBeforeMount, onBeforeUnmount, isRef, ref, reactive } from 'vue-demi'
import { isFunction, unwrap, isProxy } from './utils'
import { setValidations } from './core'
import ResultsStorage from './storage'
import { CollectFlag, nestedValidations } from './utils/injectNestedComponentValidations'
import { ComputedProxyFactory } from './utils/ComputedProxyFactory'
/**
* @typedef GlobalConfig
* @property {String} [$registerAs] - Config Object
* @property {String | Number | Symbol} [$scope] - A scope to limit child component registration
* @property {Boolean} [$stopPropagation] - Tells a Vue component to stop sending its results up to the parent
* @property {Ref<Object>} [$externalResults] - External error messages, like from server validation.
* @property {Boolean} [$autoDirty] - Should the form watch for state changed, and automatically set `$dirty` to true.
* @property {Boolean} [$lazy] - Should the validations be lazy, and run only after they are dirty
* @property {Boolean} [$rewardEarly] - Once valid, re-runs property validators only on manual calls of $commit
*/
/**
* Composition API compatible Vuelidate
* Use inside the `setup` lifecycle hook
* @param {Object | GlobalConfig} [validations] - Validations Object or the globalConfig.
* @param {Object} [state] - State object - required if `validations` is a validation object.
* @param {GlobalConfig} [globalConfig] - Config Object
* @return {ComputedRef<*>}
*/
export function useVuelidate (validations, state, globalConfig = {}) {
// if we pass only one argument, its most probably the globalConfig.
// This use case is so parents can just collect results of child forms.
if (arguments.length === 1) {
globalConfig = validations
validations = undefined
state = undefined
}
let { $registerAs, $scope = CollectFlag.COLLECT_ALL, $stopPropagation, $externalResults, currentVueInstance } = globalConfig
const instance = currentVueInstance || getCurrentInstance()?.proxy
const componentOptions = instance
? instance.$options
: {}
// if there is no registration name, add one.
if (!$registerAs && instance) {
// NOTE:
// ._uid // Vue 2.x Composition-API plugin
// .uid // Vue 3.0
const uid = instance.uid || instance._uid
$registerAs = `_vuelidate_${uid}`
}
const validationResults = ref({})
const resultsCache = new ResultsStorage()
const {
childResults,
sendValidationResultsToParent,
removeValidationResultsFromParent
} = instance
? nestedValidations({ $scope, instance })
: { childResults: ref({}) }
// Options API
if (!validations && componentOptions.validations) {
const rules = componentOptions.validations
state = ref({})
onBeforeMount(() => {
// Delay binding state to validations defined with the Options API until mounting, when the data
// has been attached to the component instance. From that point on it will be reactive.
state.value = instance
watch(() => isFunction(rules) ? rules.call(state.value, new ComputedProxyFactory(state.value)) : rules,
(validations) => {
validationResults.value = setValidations({
validations,
state,
childResults,
resultsCache,
globalConfig,
instance,
externalResults: $externalResults || instance.vuelidateExternalResults
})
}, { immediate: true })
})
globalConfig = componentOptions.validationsConfig || globalConfig
} else {
const validationsWatchTarget = isRef(validations) || isProxy(validations)
? validations
// wrap plain objects in a reactive, so we can track changes if they have computed in them.
: reactive(validations || {})
watch(validationsWatchTarget, (newValidationRules) => {
validationResults.value = setValidations({
validations: newValidationRules,
state,
childResults,
resultsCache,
globalConfig,
instance: instance ?? {},
externalResults: $externalResults
})
}, { immediate: true })
}
if (instance) {
// send all the data to the parent when the function is invoked inside setup.
sendValidationResultsToParent.forEach((f) => f(validationResults, { $registerAs, $scope, $stopPropagation }))
// before this component is destroyed, remove all the data from the parent.
onBeforeUnmount(() => removeValidationResultsFromParent.forEach((f) => f($registerAs)))
}
return computed(() => {
return {
...unwrap(validationResults.value),
...childResults.value
}
})
}
export { CollectFlag }
export default useVuelidate