Skip to content

Commit

Permalink
feat: add validateOnBlur option
Browse files Browse the repository at this point in the history
  • Loading branch information
nozomuikuta committed Jan 3, 2024
1 parent f0d2d3b commit aa5e7d5
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 20 deletions.
5 changes: 3 additions & 2 deletions packages/vue-v8n/src/composables/useV7d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import type { RuleDefinition, UseV7dOptions } from '../types'
export function useV7d<T>(value: T, rules: MaybeRefOrGetter<RuleDefinition[]>, options?: UseV7dOptions) {
const {
immediate = false,
touchOnFocus = true
touchOnFocus = true,
validateOnBlur = true
} = options || {}

const $el = ref<EventTarget>()
Expand All @@ -31,7 +32,7 @@ export function useV7d<T>(value: T, rules: MaybeRefOrGetter<RuleDefinition[]>, o

_touched.value = true

if (!isAlreadyTouched) {
if (!isAlreadyTouched && validateOnBlur) {
$el.value?.removeEventListener('blur', $validate)
$el.value?.addEventListener('blur', $validate, { once: true })
}
Expand Down
1 change: 1 addition & 0 deletions packages/vue-v8n/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface RuleContext {}
export interface UseV7dOptions {
immediate?: boolean
touchOnFocus?: boolean
validateOnBlur?: boolean
}

export interface VueV8nOptions {}
Expand Down
37 changes: 19 additions & 18 deletions playground/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,49 +30,50 @@ watch(password, () => validatedValues.passwordConfirmation = passwordConfirmatio
watch(passwordConfirmation.value, () => validatedValues.passwordConfirmation = passwordConfirmation.$validate())
watch(passwordConfirmationRuleOptions, () => validatedValues.passwordConfirmation = passwordConfirmation.$validate(), { deep: true })
const noTouchedNameRuleOptions = ref([
const noEventListeningNameRuleOptions = ref([
{ label: 'required', rule: required, selected: false },
{ label: 'min(5)', rule: min(5), selected: false },
{ label: 'max(10)', rule: max(10), selected: false }
])
const noTouchedName = useV7d('', computed(() => noTouchedNameRuleOptions.value.flatMap(({ selected, rule }) => selected ? [rule] : [])), {
touchOnFocus: false
const noEventListeningName = useV7d('', computed(() => noEventListeningNameRuleOptions.value.flatMap(({ selected, rule }) => selected ? [rule] : [])), {
touchOnFocus: false,
validateOnBlur: false
})
watch(noTouchedNameRuleOptions, () => validatedValues.noTouchedName = noTouchedName.$validate(), { deep: true })
watch(noEventListeningNameRuleOptions, () => validatedValues.noEventListeningName = noEventListeningName.$validate(), { deep: true })
const state = reactive({
name,
count,
passwordConfirmation,
noTouchedName
noEventListeningName
})
const validatedValues = reactive({} as {
name: typeof name.value.value | Error,
count: typeof count.value.value | Error,
passwordConfirmation: typeof passwordConfirmation.value.value | Error,
noTouchedName: typeof noTouchedName.value.value | Error,
noEventListeningName: typeof noEventListeningName.value.value | Error,
})
function validate() {
validatedValues.name = name.$validate()
validatedValues.count = count.$validate()
validatedValues.passwordConfirmation = passwordConfirmation.$validate()
validatedValues.noTouchedName = noTouchedName.$validate()
validatedValues.noEventListeningName = noEventListeningName.$validate()
}
function touch() {
name.$touch()
count.$touch()
passwordConfirmation.$touch()
noTouchedName.$touch()
noEventListeningName.$touch()
}
function reset() {
name.$reset()
count.$reset()
passwordConfirmation.$reset()
noTouchedName.$reset()
noEventListeningName.$reset()
}
onMounted(() => console.log(getCurrentInstance()?.appContext.config.globalProperties.vueV8n))
Expand Down Expand Up @@ -160,26 +161,26 @@ onMounted(() => console.log(getCurrentInstance()?.appContext.config.globalProper
<button @click="passwordConfirmation.$reset">Reset</button>
</div>
</div>
<div :class="['form-item', noTouchedName.$hasError.value ? 'has-error' : '']">
<label class="form-label">Name (no touched on focus):</label>
<div :class="['form-item', noEventListeningName.$hasError.value ? 'has-error' : '']">
<label class="form-label">Name (no event listening):</label>
<input
:ref="noTouchedName.$el"
:ref="noEventListeningName.$el"
type="text"
v-model="noTouchedName.value.value"
v-model="noEventListeningName.value.value"
class="form-input"
>
<p v-if="noTouchedName.$hasError.value" class="error-message">{{ noTouchedName.$error.value }}</p>
<p v-if="noEventListeningName.$hasError.value" class="error-message">{{ noEventListeningName.$error.value }}</p>
<div class="control-items">
<p>Rules:</p>
<label v-for="ruleOption in noTouchedNameRuleOptions">
<label v-for="ruleOption in noEventListeningNameRuleOptions">
<input type="checkbox" v-model="ruleOption.selected">
{{ ruleOption.label }}
</label>
</div>
<div class="control-items">
<button @click="validatedValues.noTouchedName = noTouchedName.$validate()">Validate</button>
<button @click="noTouchedName.$touch">Touch</button>
<button @click="noTouchedName.$reset">Reset</button>
<button @click="validatedValues.noEventListeningName = noEventListeningName.$validate()">Validate</button>
<button @click="noEventListeningName.$touch">Touch</button>
<button @click="noEventListeningName.$reset">Reset</button>
</div>
</div>
</div>
Expand Down

0 comments on commit aa5e7d5

Please sign in to comment.