Search code examples
vue.jsvalidationasp.net-corequasar-frameworkquasar

Server-side input validation with Quasar (Vue)


I'm looking for a reusable solution for server side input validation with Quasar Framework. I use the q-input field. There are 2 props that can be used for the error output error and error-message. My server response on a validation error is a 400 response with this json

{
  errors: { username: ['Username is to long.', 'User not valid'] },
  title: 'One or more validation errors occurred.',
  status: 400,
  traceId: '80000005-0000-ff00-b63f-84710c7967bb'
}

I am currently using this logic, but I cannot move it to a mixin because I need access to the error field. The full example is available here codesandbox.io

<q-input
  v-model="username"
  filled
  label="Username *"
  :error-message="getErrorForField('username')"
  :error="isErrorForField('username')"
/>
getErrorForField(field) {
  if (!this.errors) {
    return ''
  }
  const keys = Object.keys(this.errors)
  const key = keys.find(
    element => element.toLowerCase() === field.toLowerCase()
  )
  if (this.errors[key]) {
    return this.errors[key].join('\r\n')
  }
},
isErrorForField(field) {
  if (!this.errors) {
    return false
  }
  const keys = Object.keys(this.errors)
  const key = keys.find(
    element => element.toLowerCase() === field.toLowerCase()
  )
  if (this.errors[key]) {
    return true
  }
}

Solution

  • I have found a solution with the new vue3 composition-api. I now have a reusable logic.

    MyComponent.vue

    <template>
    <q-input
      v-model="username"
      filled
      label="Username *"
      :error-message="getErrorForField('username')"
      :error="isErrorForField('username')"
    />
    </template>
    
    <script>
    import { validationHelper } from 'src/helper/validationHelper'
    
    export default {
      name: 'MyComponent',
      setup () {
        const { showValidationError, setValidationErrors, getValidationErrors, hasValidationErrors } = validationHelper()
        return {
          showValidationError,
          setValidationErrors,
          getValidationErrors,
          hasValidationErrors
        }
      },
      methods: {
        async add () {
          try {
            //axios request
          } catch (error) {
            this.setValidationErrors(error.response.data.errors)
            this.showValidationError()
          }
        }
      }
    }
    </script>
    

    validationHelper.js

    import { ref } from '@vue/composition-api'
    
    export function validationHelper () {
      const errors = ref([])
    
      function getValidationErrorMessages (field) {
        if (!errors.value) {
          return []
        }
        const keys = Object.keys(errors.value)
        const key = keys.find(element => element.toLowerCase() === field.toLowerCase())
        if (errors.value[key]) {
          return errors.value[key]
        }
        return []
      }
    
      function getValidationErrors (field) {
        const errors = getValidationErrorMessages(field)
        if (errors.length !== 0) {
          return errors.join('\r\n')
        }
        return ''
      }
    
      function hasValidationErrors (field) {
        if (getValidationErrorMessages(field).length !== 0) {
          return true
        }
        return false
      }
    
      function setValidationErrors (payload) {
        errors.value = payload
      }
    
      function showValidationError () {
        this.$q.notify({
          type: 'negative',
          message: 'Validation failure',
          caption: 'please check the inputs'
        })
      }
    
      return {
        showValidationError,
        setValidationErrors,
        getValidationErrors,
        hasValidationErrors
      }
    }