1

I tried to create reusable components in my vue project. This is part of my training which I am going through. But I think I need a little help with my code which is confusing me.

let validations = {}

validations.firstName = function(e, that) {
  if (e.target.value == "") that.errors = {
    [that.labelID]: 'Please enter your first name'
  }
  else return true
  that.input_error = !that.input_error
}

validations.phone = function(e, that) {
  if (e.target.value == "") that.errors = {
    [that.labelID]: 'Please enter phone number'
  }
  else if (e.target.value.length > 10) that.errors = {
    [that.labelID]: 'Phone number should be 10 digits only'
  }
  else return true
  that.input_error = !that.input_error
}

validations.email = function(e, that) {
  if (e.target.value == "") that.errors = {
    [that.labelID]: 'Please enter email'
  }
  else return true
  that.input_error = !that.input_error
}

Vue.component('childInput', {
  template: '#my-child-input',
  data() {
    return {
      errors: {},
      input_error: false
    }
  },
  props: {
    labelID: String,
    label: String,
    inputType: {
      type: String,
      default: 'text'
    },
    value: {
      type: [String, Boolean, Number],
      default: null
    },
  },
  methods: {
    handleInput(e) {
      this.$emit("input", e.target.value)
    },
    handleFocusIn(e) {
      this.errors = {[this.labelID]: ''}
      if (this.input_error) this.input_error = !this.input_error
    },
    handleFocusOut(e) {
      switch (this.labelID) {
        case 'firstName':
        case 'phone':
        case 'email':
          validations[this.labelID](e, this)
          break;
        default:
          console.log('in default last name')
          break;
      }
    }
  }
});

new Vue({
  el: '#app',
  data() {
    return {
      event: {
        firstName: '',
        phone: '',
        email: ''
      }
    };
  },
  methods: {
    handleSubmit(e) {
      // I can access firstName, phone and email. 
      // But how to access the validation functions written in child component
      console.log('All data: ', this.event)
    }
  }
})
.someStyleClass {
  margin-bottom: 20px;
}

.input_error {
  border-color: red !important;
  color: red;
}

.labelStyle {
  display: block;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<!-- Parent Component -->
<div id="app">
  <div class="someStyleClass">
    <child-input v-model="event.firstName" label="First Name" label-i-d="firstName" />
  </div>
  <div class="someStyleClass">
    <child-input v-model="event.phone" label="Phone" label-i-d="phone" />
  </div>
  <div class="someStyleClass">
    <child-input v-model="event.email" label="* Email" label-i-d="email" input-type="email" />
  </div>

  <button type="submit" v-on:click="handleSubmit">Validate & Submit</button>

</div>


<!-- Child Component -->
<template id="my-child-input">
  <div>
    <label class="labelStyle" :class="{input_error}">{{ label }}</label>
    <input :class="{input_error}" :value="value" :type="[inputType]" v-on:input="handleInput" v-on:focusout="handleFocusOut" v-on:focusin="handleFocusIn"/>
    <div v-if="errors[labelID]" :class="{input_error}">{{errors[labelID]}}</div>
  </div>
</template>

I am able to validate input fields at child level and show its associated error near the input field upon focusout event. I can also access firstName, phone & email in my parent component. But when I submit the button from parent, I am unable to validate the fields. Since the validations are at child level and so are the errors.

How do I check for validations and make sure the firstName, phone & email are valid after I click the button.

Update Each time when the users inputs wrong data in the input fields the data is being validated individually at the child level. But I don't see a way to find the same in my parent component. Because my parent component's data variables are being updated simultaneously on input.

How to validate at parent level after clicking on submit without ref's and without the use of additional libraries?

2
  • You already have two-way binding in this component. Unless you need to prevent invalid values from being emitted to a parent, you need to validate value, not raw target.value Commented Jun 5, 2022 at 15:57
  • @EstusFlask I didn't think of that. Thank you for something new. However, I need to emit all values, whether valid or invalid. Only after I click the button from Parent Component I would then want to see if all of my child inputs are valid or not. Like if (firstName && phone && email) submitTheForm() else skip(). Like so. Commented Jun 5, 2022 at 21:33

1 Answer 1

1

Meybe what's you need is ref to access Child Component, here is the official documentation: https://v2.vuejs.org/v2/api/#ref

For the example in question, ref usage is:

<!-- Parent Component -->
<template>
  <div class="col-6">
    <MyInput ref="input" v-model="event.firstName" label="First Name" labelID="firstName" />
  </div>
  <!-- more element -->
  <button type="submit" v-on:click="handleSubmit">Validate & Submit</button>
</template>

<script>
export default {
  data() {
    return {
      event: { firstName: '', phone: '', email: ''}
    };
  },
  methods: {
    handleSubmit(e) {
      // this.$refs.input will be a reference of <MyInput ref="input">
      if (this.$refs.input['input_error']) {
        alert("First name is wrong")
        return;
      }
      // ...
    }
  }
}
</script>
Sign up to request clarification or add additional context in comments.

2 Comments

your solution does work but I am not looking for ref. I got 28 input fields and managing them seems cumbersome. I was hoping a way around this without having to use ref.
Oh, if you can use vuex to manage your inputs? I think that will be easier than ref. @Imran

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.