I'm in a project that's currently using vue. I'm at the moment developing validations for the inputs and in a way to make them more flexible, my idea was to create an intermediate component "Group Component" where I set as a property the input I want to load. As such, validations are imported in the component.
I've found difficulty understanding when the several inputs had passed the validations without errors in the "Page component", and to that problem I've figured out a solution, which I don't know if it's the ideal approach, since I'm using $ref
to obtain the validations of the child components and on submission it validates if all have passed.
the package I'm using for validations is vuelidate.
Is there a better approach?
Validation in submitting the form on "Page component"
onSubmit() { setTimeout(() => { if (this.checkIfAllInputsFilled()) { console.log('yes'); } else { console.log('no'); } , 300) }, checkIfAllInputsFilled() { let validationsObj = { email: this.$refs.email.$v.$invalid, password: this.$refs.password.$v.$invalid }; return Object.keys(validationsObj).every((k) => !validationsObj[k]); }
All Files - code
Page component
<template> <div class="login"> <form class="login__form" @submit.prevent="onSubmit" novalidate> <base-input-group component="Input" labelClass="authentication" :labelValue="$t('global.email')" inputId="email" inputType="email" inputName="email" inputClass="input--default input--authentication" inputValue="" :contentErrors="[ { key: 'required', message: $t('errors.gerals.required') }, { key: 'email', message: $t('errors.gerals.invalid') } ]" @get-value="form.email = $event" ref="email" /> <div class="authentication__form__buttons display--flex"> <base-button type="submit" classAttribute="button--default button--background button--authentication" :text="$t('authentication.login')" /> </div> </form> </div> </template> <script> // components const baseInputGroup = () => import( /* webpackChunkName: 'inputGroup' */ '../../../components/inputs/baseInputGroup'); const baseButton = () => import( /* webpackChunkName: 'baseButton' */ '../../../components/buttons/baseButton'); export default { components: { baseInputGroup: baseInputGroup, baseButton: baseButton }, data() { return { active: false, form: { email: '' } } }, methods: { onSubmit() { setTimeout(() => { if (this.checkIfAllInputsFilled()) { console.log('yes'); } else { console.log('no'); } }, 300) }, checkIfAllInputsFilled() { let validationsObj = { email: this.$refs.email.$v.$invalid }; return Object.keys(validationsObj).every((k) => !validationsObj[k]); } } } </script>
Group component
<template> <div class="field-group" :class="{'field--errors': $v.value.$error, 'field--success': !$v.value.$error}"> <label for="inputId" :class="`label label--${labelClass}`"> {{ labelValue }}</label> <component :is="componentInput" :inputId="inputId" :inputType="inputType" :inputName="inputName" :inputClass="inputClass" :value="inputValue" :valid="$v.value" @input-value="value = $event" /> <component v-if="$v.value.$error" :is="componentErrors" :errorMessage="errorMessage" /> </div> </template> <script> export default { props: { component: String, labelClass: String, labelValue: String, inputId: String, inputType: String, inputName: String, inputClass: String, inputValue: String, contentErrors: Array }, data () { return { componentInput: null, componentErrors: null, value: '', validator: {}, errorMessage: '' } }, created() { import(`../../../validations/${this.inputName}.js`).then( validator => { this.validator = validator.default; }); this.loaderComponent() .then(() => { this.componentInput = () => this.loaderComponent(); }) }, methods: { fillMessageError() { this.contentErrors.map( error => { if (!this.$v.value[error.key]) this.errorMessage = error.message; }); } }, computed: { loaderComponent () { return () => import( /* webpackChunkName: 'input' */ `./childrens/base${this.component}`); }, loaderComponentErrors () { return () => import( /* webpackChunkName: 'errors' */ './../errors/baseError'); } }, validations () { return { value : { ...this.validator } } }, watch: { '$v.value.$error': { deep: true, // so it detects changes to properties only handler(newVal, oldVal) { if (newVal) { if (!this.componentErrors) { this.loaderComponentErrors() .then((component) => { this.componentErrors = () => this.loaderComponentErrors(); }); } this.fillMessageError(); } else { this.$emit('get-value', this.value) } } } } } </script>
Input component
<template> <input :id="inputId" :type="inputType" :name="inputName" :class="inputClass" :value="inputValue" @blur="action" @keyup.enter="action" > </template> <script> export default { props: { inputId: String, inputType: String, inputName: String, inputClass: String, inputValue: String, valid: Object, }, methods: { action($event) { this.$emit('input-value', $event.target.value); this.valid.$touch(); } } } </script>