Vue.js Element UI form validation - showcasing errors returned by server

Utilizing Vue.js and Element UI libraries for my current project, I have implemented front-end validation with specific rules. However, I now also require the ability to display backend errors for the current field. When the form is submitted and an error is returned from the backend, it appears in the following format:

[
  {"message": "email address is invalid", "path": ["email"]},
  {"message": "example error for password field", "path": ["password"]}
]

The 'path' attribute corresponds to the field name based on the model of my form.

I have added an additional element to display backend errors, as shown in my fiddle. Nevertheless, I would like to incorporate Vue Element UI validation to ensure that backend errors are displayed in the same manner as front-end messages. Unfortunately, I am struggling to achieve this.

You can view my fiddle here: https://jsfiddle.net/ts4Lfxb6/

The form code is structured as follows:

<el-form :model="loginForm" :rules="rules" ref="loginForm" label-position="top">
      <el-form-item label="Email" prop="email">
        <el-input v-model="loginForm.email" :disabled="formProcessing" ref="loginInput"></el-input>
        <p v-if="isErrorForField('email', errors)">{{ getErrorForField('email', errors) }}</p>
      </el-form-item>
      <el-form-item label="Password" prop="password">
        <el-input v-model="loginForm.password" :disabled="formProcessing" type="password"></el-input>
        <p v-if="isErrorForField('password', errors)">{{ getErrorForField('password', errors) }}</p>
      </el-form-item>
      <el-form-item>
        <div class="submit-wrapper">
          <el-button type="primary" @click="submit('loginForm')" :loading="formProcessing">Log in</el-button>
        </div>
      </el-form-item>
    </el-form>

The complete component code is provided below:

var Main = {
  data() {
    return {
      loginForm: {
        email: '',
        password: ''
      },
      rules: {
        email: { required: true, message: 'Required', trigger: 'change' },
        password: { required: true, message: 'Required', trigger: 'change' }
      },
      formProcessing: false,
      errors: []
    }
  },
  methods: {
    isErrorForField (field, errors) {
      if (!errors && !errors.length) {
        return false
      }
      let filtered = errors.filter(error => {
        return error.path[0] === field
      })
      if (filtered.length) {
        return filtered
      }
    },
    getErrorForField (field, errors) {
      if (!errors && !errors.length) {
        return false
      }
      let filtered = errors.filter(error => {
        return error.path[0] === field
      })
      if (filtered.length) {
        return filtered[0].message
      }
    },
    supportGlobalErrorMessage () {
      this.errors.forEach(error => {
        if (!error.path.length) {
          this.$message({
            message: error.message,
            type: 'error'
          })
        }
      })
    },
    submit (formName) {
      this.$refs[formName].validate(valid => {
        if (!valid) {
          return false
        }
        this.formProcessing = true
        // send data to backend
        // error response looks like this:
        let errors = [
          {"message": "email address is invalid", "path": ["email"]},
          {"message": "example error for password field", "path": ["password"]}
        ]
        setTimeout(() => {
            this.formProcessing = false
          this.errors = errors
          this.supportGlobalErrorMessage()
        }, 500)
      })
    }
  }
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')

I'm seeking assistance with resolving this issue. Can someone provide guidance?

Answer №1

Implemented the following modifications to your code snippet:

var Main = {
  data() {
    return {
      loginForm: {
        email: '',
        password: ''
      },
      rules: {
        email: {
          required: true,
          //validator: this.customValidator,
          //trigger: 'blur'
        },
        password: {
          required: true,
          //validator: this.customValidator,
          //trigger: 'blur'
        }
      },
      formProcessing: false,
      errors: []
    }
  },
  methods: {
    customValidator(rule, value, callback) {
      console.log(rule)
      if (!value) {
        callback(new Error('The field is required'))
      }
      let errors = [{
          "message": "email address is invalid",
          "path": ["email"]
        },
        {
          "message": "example error for password field",
          "path": ["password"]
        }
      ]
      setTimeout(() => {
        this.errors = errors

        if (this.isErrorForField(rule.fullField, this.errors)) {
          callback(new Error(this.getErrorForField(rule.fullField, this.errors)))
        }
        callback()
      }, 500)
    },
    isErrorForField(field, errors) {
      if (!errors && !errors.length) {
        return false
      }
      let filtered = errors.filter(error => {
        return error.path[0] === field
      })
      if (filtered.length) {
        return filtered
      }
    },
    getErrorForField(field, errors) {
      if (!errors && !errors.length) {
        return false
      }
      let filtered = errors.filter(error => {
        return error.path[0] === field
      })
      if (filtered.length) {
        return filtered[0].message
      }
    },
    supportGlobalErrorMessage() {
      this.errors.forEach(error => {
        if (!error.path.length) {
          this.$message({
            message: error.message,
            type: 'error'
          })
        }
      })
    },
    submit(formName) {
      this.$refs[formName].validate(valid => {
        if (!valid) {
          return false
        }
        this.formProcessing = true
        // send data to backend
        // error response looks like this:
        let errors = [{
            "message": "email address is invalid",
            "path": ["email"]
          },
          {
            "message": "example error for password field",
            "path": ["password"]
          }
        ]
        setTimeout(() => {
          this.errors = errors
          this.formProcessing = false
          this.supportGlobalErrorMessage()
        }, 500)
      })
    }
  }
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
@import url("//unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1c797079717972683169755c2e322c3229">[email protected]</a>/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c4a1a8a1a9a1aab0e9b1ad84f6eaf4eaf1">[email protected]</a>/lib/index.js"></script>
<div id="app">
  <el-form :model="loginForm" :rules="rules" ref="loginForm" label-position="top">
    <el-form-item label="Email" prop="email" :error="getErrorForField('email', errors)">
      <el-input v-model="loginForm.email" :disabled="formProcessing" ref="loginInput"></el-input>
      <!-- <p v-if="isErrorForField('email', errors)">{{ getErrorForField('email', errors) }}</p> -->
    </el-form-item>
    <el-form-item label="Password" prop="password" :error="getErrorForField('password', errors)">
      <el-input v-model="loginForm.password" :disabled="formProcessing" type="password"></el-input>
      <!-- <p v-if="isErrorForField('password', errors)">{{ getErrorForField('password', errors) }}</p> -->
    </el-form-item>
    <el-form-item>
      <div class="submit-wrapper">
        <el-button type="primary" @click="submit('loginForm')" :loading="formProcessing">Log in</el-button>
      </div>
    </el-form-item>
  </el-form>
</div>

The validator property within the rules attribute allows setting a customized validation rule that takes three parameters (rule, value, callback).

rule: Represents the validation rule in the source descriptor corresponding to the field name being validated.

value: Indicates the value of the source object property undergoing validation.

callback: A function to trigger once validation is done, usually expecting an array of Error instances to signal validation failure. Synchronous checks can directly return false or Error/ Error Array.

This setup enables fetching and processing backend data, followed by displaying any error messages through the callback.

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

The images in the React slick carousel appear to be slightly out of

I'm experiencing blurriness in my carousel when it animates with card items. Despite searching for a solution, I haven't found one yet. My tech stack includes Next.js and TypeScript. const ref = useRef<any>(); const settings = { arro ...

What is causing the datepicker to return null value?

Having a dilemma with two textboxes named start_date and end_date. Every time I click the search button, it appears to return a null value. I am trying to find a way to alert and display the value inside these textboxes. It seems like the issue arises wh ...

Encountering errors while running Angular 8's ng build prod command

After successfully migrating my project from Angular 7 to Angular 8, I encountered an issue when attempting to run 'ng build prod' which resulted in the following error: ERROR in Error during template compile of 'Ng2CompleterModule' Cou ...

The table's content extends beyond the confines of the page

I have an HTML page where I am embedding an SSRS report. The report extends beyond the page as shown in the image below: This is the table that is generated: <table cellpadding="0" cellspacing="0" id="ctl00_MainContent_FiveYearReportViewer_fixedTable" ...

How to send parameters to the jquery .css() method

I'm attempting to create hyperlinks that can dynamically set inline styles for different elements on a webpage. I have managed to save the element and attribute settings in hidden span elements and retrieve them to display in an alert dialog. However, ...

Utilizing CDN for Vuetify in Vue.js and Laravel instead of relying on npm install

I'm looking to reduce the size of my app.js file. Is it possible to import Vuetify from a CDN/UNPKG inside my app.js? Will the load time be the same if I import it locally via npm install compared to using a CDN? I've managed to reduce file size ...

How can I create a slot component with a prop defined in the child component?

If I have three components called Alpha, Bravo, and Charlie. Here is how they are structured: Alpha.vue <template> <div class="alpha"> <bravo> <template slot="card"> <charlie></cha ...

A guide on designing a personalized search bar for MUI-Datatables with a sleek outlined style

Check out the default UI from MUI-Datatables v4.3.0 here: https://i.stack.imgur.com/rbHgD.png I want to create a style similar to this: https://i.stack.imgur.com/AUHqC.png Just so you know, I am using the following packages: "@mui/material": &q ...

I am facing difficulties accessing an element within a controller in Angular

Struggling to access an element inside an AngularJS controller, I attempted the following: var imageInput = document.getElementById("myImage"); Unfortunately, this approach was unsuccessful as the element returned null. Curiously, when placing the statem ...

Is it possible to dynamically assign a template reference variable to a newly created DOM element in TypeScript?

After creating a DOM element with this.document.createElement('h1'), I am looking to insert the element into a section tag using a template reference variable (myTRF), similar to the example below: <section> <h1 #myTRF>This is my he ...

Dynamic styling based on conditions in Next.js

After a lengthy hiatus, I'm diving back in and feeling somewhat disconnected. In short, I have encountered a minor challenge. I successfully created a navigation menu pop-out that toggles classname based on the isActive condition in React. However, I& ...

Send a redirect after a certain delay to a URL stored in a variable outside of the current scope

Upon making an ajax request, the JSON response contains a link that needs to redirect the user to another page after 3 seconds. The current approach used is: response = JSON.parse(res); var link = response.link; setTimeout("window.location.href=link",300 ...

What is the best way to use HTML5 canvas and JavaScript to crop an image offline?

While there are many online tools available to crop an image using JavaScript and PHP, the challenge arises when we want our app to function strictly offline without relying on server-side PHP scripting. In order to achieve this, we must turn to HTML5 ca ...

React: Issue with input values not correctly updating across multiple fields when changing state toggles

I am working on a React component that needs to update input values for multiple players independently. However, I am facing an issue where toggling a state causes the first input's value to incorrectly propagate to all other inputs. Additionally, cle ...

Changing a collection of values in an object into a designated array shape

I have an object with the following values: const data = { "generalInfo": [{ "title": "title1", "permalink": "www.link.com", "manufacturer": "manufacturer1", "category": [{ "term_id": 3 ...

Vue.js is unable to dispatch an event to the $root element

I'm having trouble sending an event to the root component. I want to emit the event when the user presses enter, and have the root component receive it and execute a function that will add the message to an array. JavaScript: Vue.component('inp ...

Using the clientWidth property in React

While I have a solid background in Javascript, I am relatively new to working with React. In my previous projects where I coded directly in javascript for the browser, I frequently used the following code snippet: width = document.getElementById('elem ...

Typescript - Conditional imports

When working with the moment-timezone module, one issue that arises is receiving a warning if it is included multiple times. In my specific case, I have a module that necessitates the use of this timezone functionality. Since I am unsure whether or not the ...

"Android Webview's evaluateJavascript function is not returning the expected value

I am attempting to retrieve the username from a webview, but it is returning a null object. webView.settings.javaScriptEnabled = true webView.evaluateJavascript( "(function() { return document.getElementsByClassName('lgn-loginname') })() ...

Error Alert: JQuery Pop Up Issue

Struggling with getting my JQuery Pop-Up Box to work properly. Any guidance for a newbie like me on how to fix it would be greatly appreciated. Here's the code I've been working on: <!-- POP UP HTML --> <div class="infocontainer"> ...