0

I want to bind a class to an element based on the result of a boolean expression. For example:

<input type="email" :class="{ invalid: submitted && $v.email.$error }">

But the "invalid" class is not added to the element if I evaluate both conditions; it only works when I evaluate one or the other, for example:

<input type="email" :class="{ invalid: submitted }">

or

<input type="email" :class="{ invalid: $v.email.$error }">

work just fine. I realize I could use computed properties for this, but I'd have to create a computed property for each field in my web form and that seems redundant. Is there a better way?

bumbleshoot
  • 1,082
  • 2
  • 17
  • 32

3 Answers3

0
<input type="email" :class="{ invalid: formValid($v.email.$error) }">

    computed: {
        formValid(){
           return (val) {
                val && this.submitted ? true : false
            }
         }     
    }

Could you test this out im curious if it would work, then you just have to pass a param and need one Computed.

niclas_4
  • 3,514
  • 1
  • 18
  • 49
0

Your Code

<input type="email" :class="{ invalid: submitted && $v.email.$error }">

The problem here, even though you defined $v in your local state, Vue is unable to find it. Try to define your local state in your data property without a preceding dollar sign. Because $ carries an extra meaning in Vue.

Generally $ means instance properties like data, el, root, children etc. For example to access what element your Vue instance is mounted on, you can use this.$el. So you can modify your code like this -

<input type="email" :class="{ invalid: submitted && $data.$v.email.$error }">
santanu bera
  • 1,281
  • 10
  • 16
  • $v is created by the Vuelidate plugin, and I know it exists because my third code example works. – bumbleshoot Nov 02 '18 at 07:11
  • I have updated my answer, all you have to do to add "$data" before "$v.email.$error". Now it will work just as expected. – santanu bera Nov 02 '18 at 07:13
  • I don't know how your third example is working. Your statement leads me to JSBIN to try it out. But for me it doesn't work. https://jsbin.com/niwimahaqe/edit?html,css,js,console,output – santanu bera Nov 02 '18 at 07:25
  • Thanks for trying... but when I add `$data` I get `TypeError: Cannot read property 'email' of undefined`. :( – bumbleshoot Nov 02 '18 at 07:28
  • In the above link, try adding "$data" before "$submitted", you will see the changes. Sorry, the first link is invalid. – santanu bera Nov 02 '18 at 07:32
0

I think I've found a pretty good solution. I used a method with an argument instead of computed properties:

<template>
  <form @submit.prevent="onSubmit" novalidate>
    <input
      type="email"
      :class="{ invalid: isInvalid($v.email.$error) }"
      v-model.lazy="email">
    <button type="submit">Submit</button>
  </form>
</template>

<script>
import { required, email } from 'vuelidate/lib/validators'

export default {
  data () {
    return {
      email: '',
      submitted: false
    }
  },
  validations: {
    email: {
      required,
      email
    },
  },
  methods: {
    isInvalid (val) {
      return val && this.submitted
    },
    onSubmit () {
      this.submitted = true
      if (!this.$v.$invalid) {
        // do something with the email address
      }
    }
  }
}
</script>
bumbleshoot
  • 1,082
  • 2
  • 17
  • 32