Terje Nygård
Terje Nygård

Reputation: 1257

VUE : Vuelidate between. Using max value from store value?

I'm using VUE and Vuelidate for validating form input. In this case.. It's a modal popup which gets data through ...mapGetters from the store.

If i set static values like this, it works :

validations: {
        refundAmount: {
            between: between(0, 40)
        }
    },

but when using a value from the store like this, it doesn't map against the value :

validations: {
        refundAmount: {
            between: between(0, this.selectedOrder ? this.selectedOrder.totalprice : 0)
        }
    },

My hard guess... this.selectedOrder.totalprice is not existing before the vuelidate component needs it ? Not sure how to actually handle that one...

The current validation (between) accepts only from 0 to 0 (zero to zero) so clearly... the value from this.selectedOrder.totalprice is not existant...

Here is my code :

import bus from '../global/bus.js'
import {
  mapGetters
} from "vuex"
import {
  required,
  minLength,
  between
} from 'vuelidate/lib/validators'

var moment = require('moment')
var alertify = require('../assets/alertify.js')

export default {
  name: "modal",
  data() {
    return {
      comment: null,
      refundAmount: null,
      paymentOptionsAgreementId: null,
      moveToAppId: null
    }
  },
  validations: {
    refundAmount: {
      between: between(0, this.selectedOrder ? this.selectedOrder.totalprice : 0)
    }
  },
  mounted() {
    this.$v.$touch()
  },
  computed: {
    ...mapGetters(["visibleModalComponent", "selectedOrder", "loggedInUser", "accessToken", "paymentoptions"])
  }
}
<template>
  
  <div class="form-group">
                                <label class="col-sm-5">Refundér beløp</label>
                                <div class="col-sm-7">
                                    <input
                                        v-model.trim="refundAmount" 
                                        v-on:input="$v.refundAmount.$touch" 
                                        v-bind:class="{error: $v.refundAmount.$error, 
                                                       valid: $v.refundAmount.$dirty && 
                                                       !$v.refundAmount.$invalid}"
                                        type="text" 
                                        class="form-control">
                                    </input>
                                    <pre>{{ $v }}</pre>
                                   
                                </div>
                            </div>
  
</template

Updated with computed value (sat correctly), but still not working :

Computed code :

computed: {
        ...mapGetters(["visibleModalComponent", "selectedOrder", "loggedInUser", "accessToken", "paymentoptions"]),
        totalPrice() {
            return this.selectedOrder ? this.selectedOrder.totalprice : 0
        }
    },

Validation :

validations: {
        refundAmount: {
            between: between(0, this.totalPrice)
        }
    },

Screenshot :

enter image description here

Upvotes: 4

Views: 9109

Answers (2)

Mark Mottian
Mark Mottian

Reputation: 71

Change the Validation scheme to be dynamic as explained here https://vuelidate.js.org/#sub-dynamic-validation-schema

For example, validations are usually defined like this:

 validations: {
        refundAmount: {
            between: between(0, this.selectedOrder ? 
               this.selectedOrder.totalprice : 0)
        }
 }

Change validations object to a function as follows:

validations () { 
     return {
         refundAmount: {
             between: between(0, this.selectedOrder ?                                           
             this.selectedOrder.totalprice : 0)
         }
    }
}

This makes the validation schema dynamic, thereby allowing the component's data, including Vuex store data, to be accessible to built-in Vuelidate validators such as minLength, maxLength etc. , as well as custom validators using the this keyword.

Upvotes: 1

Richard Matsen
Richard Matsen

Reputation: 23483

Try a computed value for totalPrice.

export default {
  name: "modal",
  data() {
    return {
      comment: null,
      refundAmount: null,
      paymentOptionsAgreementId: null,
      moveToAppId: null
    }
  },
  validations: {
    refundAmount: {
      between: between(0, this.totalprice)
    }
  },
  computed: {
    ...mapGetters(["visibleModalComponent", "selectedOrder", "loggedInUser", "accessToken", "paymentoptions"]),
    totalPrice() {
      return this.selectedOrder ? this.selectedOrder.totalprice : 0
    }
  } 

Edit After collaborative effort with Terje, we have the following fix:

Vuelidate requires a function to be able to use variables as parameters to it's validations, so the working code is

validations: {
  refundAmount: {
    // between: between(0, this.totalPrice)
    between (value) {
      return between(0, this.totalPrice)(value)
    }
  }
},

Ref: Is it possible to use a variable for validation? #55

Upvotes: 4

Related Questions