ragnarlotus/vue-daval

Start and End Date validation

Closed this issue · 7 comments

I have a bunch of models that have start and end date properties and I need to validate:

  • start date < end date
  • end date > start date

also sometimes need

  • start date <= end date
  • end date >= start date

Do you have any ideas for how to generically handle this?

Is there anyway within a validation rule to access other properties of the model being validated?

Hello, in that case, the only way to do it is using the Custom validatior so you can create your own function to validate. The function is bound to the Vue instance, so just using $this inside the function you should be able to reach the model.

Regards

Thanks for the reply,

It's been a while since I worked with VUE so I might be doing something wrong; within my custom validation function I don't see any $this object that is the model being validated.

image

After some digging around in the objects I came up with this. Please let me know if I'm going in a bad direction, or if you have a better way. I'm trying to keep the actual validation method as generic as possible, so I pass in the names from the rules json.

  startDate: {
    field: 'Start Date',
    required: true,
    type: 'date',
    checkDate: validators.checkDateLtDate('startDate', 'endDate')
  },

export function checkDateLtDate (startDateName: string, endDateName: string) {
  return function (value: Date, $this: any) {
    let startDateValue = $this.$parent.$data[startDateName]
    let endDateValue = $this.$parent.$data[endDateName]
    let startDateDisplayName = $this.$parent.$rules[startDateName].field
    let endDateDisplayhName = $this.$parent.$rules[endDateName].field
    return moment(startDateValue).isBefore(endDateValue, 'day') ? true : `${startDateDisplayName} must be before ${endDateDisplayhName}`
  }
}

Now I have a related question. How can I force a the startDate to re-validate when the endDate changes? If I change startDate to be after endDate (invalid) and then update the endDate to be after the startDate so they should both be valid now, the UI still shows the startDate as being invalid because it hasn't re-validated.

image

Sorry, yesterday I was busy at work, I will try get up to date and answer you as soon as posible.

Regards.

First of all sorry, I mistakenly told you $this when I meant just this.

As you can see in you debugging screenshot, you have all the vue instance in it, so like I said you can access all the data using this.ANYVARNAME.

Your function does not even need to receive the first parameter because you will use the data directly from the vue instance, and the second parameter is just the object DataPath which you don't need.

So what you really need is something like:

export function checkDateLtDate() {
    let startDateValue = this.startDateValue // Not sure of the names of this vars in your data
    let endDateValue = this.endDateValue // Not sure of the names of this vars in your data
    let startDateDisplayName = this.startDateName // Not sure of the names of this vars in your data
    let endDateDisplayhName = this.endDateName // Not sure of the names of this vars in your data
    return moment(startDateValue).isBefore(endDateValue, 'day') ? true : `${startDateDisplayName} must be before ${endDateDisplayhName}`
}

I'm not 100% sure without seeing the whole component.

And about the to trigger the startDate revalidation when endDate changes, you can use the links functionality, or just use a watcher to detect when the endDate changes and runs this:

    this.$vd.startDate.$validate(true)

The parameter passed to true is to force the revalidation, because it is cached as the value didn't change it wouldn't really notice, so that way we force it to check all rules again.

Hope that this helps you, and sorry again for the late response.

Cheers!

I ended up putting a watch on the entire model and then running all the validation

  @Watch('company', {deep: true})
  onCompanyChanged (value: any, oldValue: any) {
    this.$vd.company.$validate(true)
  }

Thanks