Create unique error messages using Vue validators

Two fields named text and email are included in my template. Below is the structure of the template:

HTML

<!DOCTYPE html>
<html>
<head>
    <title>Vue - Validations</title>
    <script src="Libraries/vue/vue.min.js"></script>
    <script src="Libraries/vue/vuelidate.min.js"></script>
    <script src="Libraries/vue/validators.min.js"></script>
</head>
<body>
<div id="app">
    <h2>Form Validation</h2>
    <input v-model="text" v-on:blur="$v.text.$touch()" :class="status($v.text)">
    <p style="color:red;">{{textErrMsg}}</p>
    <input v-model="email" v-on:blur="$v.email.$touch()" :class="status($v.email)">
    <p style="color:red;">{{emailErrMsg}}</p>
  <pre>{{ $v }}</pre>
</div>
<script src="app.js"></script>
</body>
</html>

JS

Vue.use(window.vuelidate.default)
const { required, minLength,email, numeric, minValue } = window.validators
new Vue({
    el: "#app",
  data: {
    text: '',
    email: '',
    textErrMsg: '',
    emailErrMsg: ''
  },
  validations: {
    text: {
      required,
      minLength: minLength(5)
    },
    email: {
     required,
     email
    }
  },
  methods: {
    status(validation) {
        return {
        error: validation.$error,
        dirty: validation.$dirty
        
         if(validation.text.required){
           this.textErrMsg == "Text is required";
         } else if(validation.text.minLength){
         this.textErrMsg == "Text must be 5 characters";
         }
         
         if(validation.email.required){
           this.emailErrMsg == "Email is required";
         } else if(validation.email.email){
         this.emailErrMsg == "Enter valid email";
         }
      }
    }
  }
})

The goal is to detect validation failure conditions such as required, email, minLength, etc., in the JavaScript file so that appropriate messages can be displayed in the template.

Instead of handling this directly in the template.

<p>{{!$v.text.required ? 'Text is required': !$v.text.minLength ? 'Text must be 5 characters' : '' }}</p>

Access Fiddle link

Answer №1

I have devised two solutions for your issue. The initial one is constructed based on your existing code and the key/value pairs linked to our inputs. On the other hand, the second solution utilizes an inputs object where I iterate through all values to formulate the form.

To enhance the error handling process, I introduced an errorMessages object instead of a mere error string for each value. Moreover, I updated it using vm.$set.

Vue.use(window.vuelidate.default)
const { required, minLength, email } = window.validators

// SOLUTION 1
new Vue({
  el: "#app",
  data() {
    return {
      text: '',
      email: '',
      errorMessages: {},
    }
  },
  validations: {
    text: {
      required,
      minLength: minLength(5)
    },
    email: {
      required,
      email
    }
  },
  methods: {
    status(e) {
      const name = e.target.name;
      const currentValidation = this.$v[name];

      // Reset initially
      this.$set(this.errorMessages, name, "");

      if(!currentValidation.required){
        this.$set(this.errorMessages, name, "Is required");
      } 
      if(typeof currentValidation.minLength !== 'undefined' && !currentValidation.minLength){
        this.$set(this.errorMessages, name, "Must be 5 characters");
      }

      // Email validation
      if(
        typeof currentValidation.email !== 'undefined' && 
        !currentValidation.email && 
        currentValidation.$invalid
      ) {
        this.$set(this.errorMessages, name, "Must be an email");
      }

    }
  }
});

// -------------------------

// SOLUTION 2
new Vue({
  el: "#app2",
  data() {
    return {
      inputs: {
        text: {
          value: '',
          title: 'Text',
          error: ''
        }, 
        email: {
          value: '',
          title: 'E-Mail',
          error: ''
        }, 
      },
      errorMessages: {},
    }
  },
  validations: {
    inputs: {
      text: {
        value: {
          required,
          minLength: minLength(5)
        }
      },
      email: {
        value: {
          required,
          email
        }
      },
    }
  },
  methods: {
    edit(e) {
      const value = e.target.value;
      const name = e.target.name;
      const currentValidation = this.$v.inputs[name].value;
      const currentInput = this.inputs[name];

      // Set the value
      this.$set(currentInput, 'value', value);

      // Reset
      this.$set(currentInput, 'error', '');

      // Implementing validations
      if(!currentValidation.required){
        this.$set(currentInput, 'error', "Is required");
      } 
      if(typeof currentValidation.minLength !== 'undefined' && !currentValidation.minLength){
        this.$set(currentInput, 'error',"Must be 5 characters");
      }


      if(
        typeof currentValidation.email !== 'undefined' && 
        !currentValidation.email && 
        currentValidation.$invalid
      ) {
        this.$set(currentInput, 'error', "Must be an email");
      }

    }
  }
})
input {
  border: 1px solid silver;
  border-radius: 4px;
  background: white;
  padding: 5px 10px;
}

.dirty {
  border-color: #5A5;
  background: #EFE;
}

.dirty:focus {
  outline-color: #8E8;
}

.error {
  border-color: red;
  background: #FDD;
}

.error:focus {
  outline-color: #F99;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="44323121282d2025302104746a736a71">[email protected]</a>/dist/validators.min.js"></script>
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="05737060696c6164716045352b322b30">[email protected]</a>/dist/vuelidate.min.js"></script>

<div id="app">
  <h3>Form Validation</h3>
  <input 
    v-model="text" 
    name="text"
    @input="status"
    @focus="status"
    @blur="$v.text.$touch()" 
  />

  <p style="color:red;">{{errorMessages.text}}</p>

  <input 
    v-model="email" 
    name="email"
    @input="status"
    @focus="status"
    @blur="$v.email.$touch()" 
  />

  <p style="color:red;">{{errorMessages.email}}</p>
</div>

<h1>Group</h1>

<div id="app2">
  <h3>Form Validation</h3>
  
  <template v-for="(input, name) in inputs">
    {{input.title}}
    <input 
      :value="input.value"
      :name="name"
      @input="edit"
      @blur="$v[name].$touch()" 
    />

    <p style="color:red;">{{input.error}}</p>
  </template>

  
  <pre>{{ inputs }}</pre>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I show a title when redirecting a URL in VUE JS?

My current setup includes a navigation drawer component that changes the title based on the user's route. For example, when navigating to the home page (e.g. "/"), the title updates to "Home", and when navigating to the profile page (e.g. /profile), t ...

The callback response in Node's exec function is behaving incorrectly

When I have a route handling a URL post request, I am running an exec on a bash command. Strangely, the console.log is working fine indicating that the bash command ends and the callback is triggered. However, for some reason, the response fails to send ...

Arrange an asynchronous function in Node.js

I have been attempting to set up a schedule for an asynchronous function (with async/await return type) to run every two minutes. Although I have tried using the generic setInterval, as well as various node modules such as node-schedule, cron, node-cron, ...

Is it possible for Angular to complete all input validations rather than stopping at the first validation failure?

I'm struggling to get Angular to display all input validations simultaneously. Check out this example on jsfiddle that showcases the issue http://jsfiddle.net/carpasse/GDDE2/ When you enter just 1 character in the email input, you'll see the er ...

Integrating a parameter into a plugin allows for displaying a specified number of elements in the output

A unique plugin is being used to create a vertical slideshow effect. This plugin scrolls the top-most div in a series of divs with the same class upwards, removes it from the container, and appends it to the bottom of the series within the container. The e ...

VueJS Unit Testing: Exploring the Content of Attributes- What to Test?

I'm currently facing some challenges with my initial VueJS unit tests using Jest. Although I grasp the concept and have already executed my first set of successful tests, I find myself pondering over the question of "What aspects should I test?" For ...

Issues with sending FormData through Ajax POST requests over a secure HTTPS connection

We are currently experiencing issues with uploading pictures to our server. The process works smoothly on http sites, but encounters errors on https sites. An error message is displayed: Failed to load resource: the server responded with a status of 500 ( ...

Is there any functionality provided by vue.js filters that cannot be achieved with nested methods?

Is there a significant advantage to using vue.js filters over nested methods? As a newcomer to vue.js, it seems like additional syntax with little tangible benefit. For example, instead of utilizing the "capitalize" function in filters as shown below: {{ ...

Tips for effectively managing the timeout of server-side AJAX calls1. Maxim

I'm currently developing server code in ASP.NET with the MVC framework. The client-side code is written in javascript. When sending an AJAX request from the browser to the server, whether using JQuery or not, timeouts can be set. Additionally, the br ...

Error in VueJS: Computed property not updating as expected due to lacking a setter function (which is

I've created a Wrapper component that wraps a third-party component. Here's how it looks: <template> <custom-element v-model="computedProperty" > </custom-element> </template> <script> export default { ...

What is the process for sending values to a component?

I am working with a component called MyComponent: export class MyComponent { @Input() active:boolean; constructor() { console.log(this.active); } } In this component, I have declared an Input, and I pass it in as follows: <mycomp ...

Invoking a function within the directive's controller

How can I access and call the method defined within the directive controller externally? <div ng-controller="MyCtrl"> <map></map> <button ng-click="updateMap()">call updateMap()</button> </div> app.directive(&a ...

Changing the location of an ArcGIS map with a click event in a Vue application

I am attempting to dynamically update a map to display my current location using Vue. I have created an onClick event that updates the props and sends them to my map component. To trigger a re-render of the map component when the data changes, I am utilizi ...

How come once I close a PrimeNG modal that is defined within a child component, I am unable to reopen it?

Currently, I am developing an Angular application that utilizes PrimeNG. In the process, I encountered a challenge. Initially, I had a component with a PrimeNG Dialog embedded within (refer to this link), and it was functioning properly. To streamline my ...

What is the reason behind the lag caused by setTimeout() in my application, while RxJS timer().subscribe(...) does not have the same

I am currently working on a component that "lazy loads" some comments every 100ms. However, I noticed that when I use setTimeout for this task, the performance of my application suffers significantly. Here is a snippet from the component: <div *ngFor ...

The Discord.js command outright declines to function

I'm having trouble with a code that I'm working on. The goal is to create a command that is enabled by default, but once a user uses it, it should be disabled for that user. However, when I try to execute the code, it doesn't work at all and ...

Exploring the Contrast between router-link and RouterLink in VueIn this article

During my exploration of Vue Router, I noticed that I could use both <router-link> and RouterLink to accomplish the same task of navigating between different routes. Similarly, there's the existence of <router-view> alongside the RouterVi ...

Run module following a POST request

I am currently working on integrating real-time information transmission through sockets using socket.io, along with push notifications sent via the OneSignal platform. However, I have encountered an issue where placing both functionalities in the same mo ...

Make real-time edits to JavaScript code on a webpage

Is there a method aside from using Firebug in the DOM view to edit live JavaScript embedded within an HTML page? For example, code like this within a .html file: <script type="text/javascript> // code here </script> Thank you. ...

Adding child arrays to a parent array in Angular 8 using push method

Upon filtering the data, the response obtained inside the findChildrens function is as follows: My expectation now is that if the object length of this.newRegion is greater than 1, then merge the children of the second object into the parent object's ...