Vuelidate example

by duleorlovic

HTML

<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.23.0/ramda.min.js"></script>
<div id="app">
  On client-side we have "required" validation and age between 20 and 30<br>
  Simulated server promise returns error if name length or age is odd.<br>
  Note that server errors are shown on Submit (and cleared on input update).
  <form @submit.prevent="submit">

    <p>
      <input
        type="text"
        v-model="name"
        v-on:input="$v.name.$touch"
        v-bind:class="{'error-input': hasError('name')}"
        >
       <span
         class='error-message'
         v-if='hasError("name") && nameServerError === null'
         >
         This is a required field
       </span>
       <span
         class='error-message'
         v-if='hasError("name") && nameServerError != null'
         >
         Error: {{ nameServerError }}
       </span>
    </p>
    <p>
      <input
        type="number"
        v-model="age"
        v-on:input="$v.age.$touch"
        v-bind:class="{error: hasError('age')}"
        >
       <span
         class='error-message'
         v-if='hasError("age") && ageServerError === null'
         >
         Age must be between 20 and 30
       </span>
       <span
         class='error-message'
         v-if='hasError("age") && age != null'
         >
         Error: {{ ageServerError }}
       </span>
    </p>
    <p>
      <button type='submit'>
        Submit
      </button>
      <span v-if='showLoader'>waiting for server response...</span>
    </p>
  </form>
  <pre>{{ $v }}</pre>
</div>

CSS

.error-input {
  border-color: red;
}
.error-message {
  color: red;
}

Babel + JSX

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

const validateFromServer = fieldName => function() {
  if (this.validationPromise) {
    // until we get response, serverSaidOK will be false, but validation will
    // not be triggered untill this promise is resolved or rejected
    return this.validationPromise
      // return true to mark success validation in case we successfully get
      // result (otherwise, validateFromServer will return null in this case)
      .then(() => true)
      .catch(response => {
        // return false in case there is an http error and data.errors for
        // fieldName exists
        if (response.errors[fieldName] === undefined) {
          console.log(`validateFromServer ${fieldName} true ${JSON.stringify(response)}`)
          return true
        } else {
          const fieldNameForServerError = fieldName + 'ServerError'
          this[fieldNameForServerError] = response.errors[fieldName].join()
          console.log(`validateFromServer ${fieldName} = ${this[fieldNameForServerError]}`)
          return false
        }
      })
      .finally(() => {
        this.showLoader = false
      })
  } else {
    console.log(`validateFromServer ${fieldName} true because validationPromise is null`)
    return true
  }
}

const simulateServerErrorsPromise = function(name, age) {
  return new Promise((resolutitonFunc, rejectionFunc) => {
    setTimeout(() => {
      if (name.length % 2 == 0 && age % 2 == 0) {
        const successResponse = {
          message: `name='${name}' length is even and age=${age} is even`
        }
        resolutitonFunc(successResponse)
      } else {
        var errorResponse
        if (name.length % 2 != 0 && age % 2 == 0) {
          errorResponse = {
            errors: {
              name: [`name='${name}' length is NOT even`]
            }
          }
        } else if (name.length % 2 == 0 && age % 2 != 0) {
          errorResponse = {
            errors: {
      ...