UNPKG

vuetify

Version:

Vue.js 2 Semantic Component Framework

205 lines (187 loc) 4.78 kB
import { deepEqual } from '../util/helpers' import { inject as RegistrableInject } from './registrable' import { consoleError } from '../util/console' // Mixins import Colorable from './colorable' /* @vue/component */ export default { name: 'validatable', mixins: [ Colorable, RegistrableInject('form') ], props: { disabled: Boolean, error: Boolean, errorCount: { type: [Number, String], default: 1 }, errorMessages: { type: [String, Array], default: () => [] }, messages: { type: [String, Array], default: () => [] }, readonly: Boolean, rules: { type: Array, default: () => [] }, success: Boolean, successMessages: { type: [String, Array], default: () => [] }, validateOnBlur: Boolean }, data: () => ({ errorBucket: [], hasColor: false, hasFocused: false, hasInput: false, isFocused: false, isResetting: false, valid: false }), computed: { hasError () { return this.internalErrorMessages.length > 0 || this.errorBucket.length > 0 || this.error }, externalError () { return this.internalErrorMessages.length > 0 || this.error }, // TODO: Add logic that allows the user to enable based // upon a good validation hasSuccess () { return this.successMessages.length > 0 || this.success }, hasMessages () { return this.validations.length > 0 }, hasState () { return this.hasSuccess || (this.shouldValidate && this.hasError) }, internalErrorMessages () { return this.errorMessages || '' }, shouldValidate () { return this.externalError || (!this.isResetting && ( this.validateOnBlur ? this.hasFocused && !this.isFocused : (this.hasInput || this.hasFocused) )) }, validations () { return this.validationTarget.slice(0, this.errorCount) }, validationState () { if (this.hasError && this.shouldValidate) return 'error' if (this.hasSuccess) return 'success' if (this.hasColor) return this.color return null }, validationTarget () { const target = this.internalErrorMessages.length > 0 ? this.errorMessages : this.successMessages.length > 0 ? this.successMessages : this.messages // String if (!Array.isArray(target)) { return [target] // Array with items } else if (target.length > 0) { return target // Currently has validation } else if (this.shouldValidate) { return this.errorBucket } else { return [] } } }, watch: { rules: { handler (newVal, oldVal) { if (deepEqual(newVal, oldVal)) return this.validate() }, deep: true }, internalValue () { // If it's the first time we're setting input, // mark it with hasInput this.hasInput = true this.validateOnBlur || this.$nextTick(this.validate) }, isFocused (val) { // Should not check validation // if disabled or readonly if ( !val && !this.disabled && !this.readonly ) { this.hasFocused = true this.validateOnBlur && this.validate() } }, isResetting () { setTimeout(() => { this.hasInput = false this.hasFocused = false this.isResetting = false }, 0) }, hasError (val) { if (this.shouldValidate) { this.$emit('update:error', val) } } }, beforeMount () { this.validate() }, created () { this.form && this.form.register(this) }, beforeDestroy () { this.form && this.form.unregister(this) }, methods: { /** @public */ reset () { this.isResetting = true this.internalValue = Array.isArray(this.internalValue) ? [] : undefined }, /** @public */ resetValidation () { this.isResetting = true }, /** @public */ validate (force = false, value = this.internalValue) { const errorBucket = [] if (force) this.hasInput = this.hasFocused = true for (let index = 0; index < this.rules.length; index++) { const rule = this.rules[index] const valid = typeof rule === 'function' ? rule(value) : rule if (valid === false || typeof valid === 'string') { errorBucket.push(valid) } else if (valid !== true) { consoleError(`Rules should return a string or boolean, received '${typeof valid}' instead`, this) } } this.errorBucket = errorBucket this.valid = errorBucket.length === 0 return this.valid } } }