Vee-validate: required_if rule issue

Created on 6 Mar 2020  Â·  8Comments  Â·  Source: logaretm/vee-validate

Versions

  • vee-validate: 3.2.5
  • vue: 2.6.11

Describe the bug
required_if field is not set to invalid

To reproduce
Steps to reproduce the behavior:

  1. Go to here https://codesandbox.io/s/wizardly-agnesi-gztg2
  2. Type foo into the first field

Expected behavior
Once you type "foo" and blur the first field, the second field should be considered invalid because it should be considered required at that time and its value is empty.

Not "failed", or have errors in its errors list because there's been no user interaction on the second field and validation is set to "eager"

Demo link
https://codesandbox.io/s/wizardly-agnesi-gztg2

Desktop (please complete the following information):

  • OS: macOS Mojave 10.14.5 (18F132)
  • Browser: Chrome
  • Version: 80.0.3987.122 (Official Build) (64-bit)

All 8 comments

This is expected, initially vee-validate checks the fields for errors to set the invalid state. Then if the field is interacted with, it will be updated. Otherwise, it will stay the same.

This is true for all interaction modes, I know this could be confusing sometimes especially with rules like required_if but that's how it's designed for cross-field validation.

Anyways, you should call handeSubmit on the validation observer which should mitigate such problems. However, I will consider this for v4.

That seems counterintuitive, but i understand, thanks for taking the time to respond.

If anyone else stumbles upon this in the future expecting the behavior i described, my current workaround is to just call observer.validate({ silent: true }); which will update the required_if fields

Well, let's change the example, assuming you have the confirmed rule. It shouldn't be marked invalid unless the field has been touched, even if the other field changed.

In that scenario it makes sense, you don't want the cross-field validation to be aggressive. But with required_if it sounds counterintuitive like you said, but unfortunately, I have to ensure consistency.

In that situation I would expect the fields to be invalid but not failed,
because they are not valid.

On Sat, Mar 7, 2020 at 5:22 PM Abdelrahman Awad notifications@github.com
wrote:

Well, let's change the example, assuming you have the confirmed rule. It
shouldn't be marked invalid unless the field has been touched, even if the
other field changed.

In that scenario it makes sense, you don't want the cross-field
validation to be aggressive. But with required_if it sounds
counterintuitive like you said, but unfortunately, I have to ensure
consistency.

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/logaretm/vee-validate/issues/2681?email_source=notifications&email_token=ACBML7VKF7YXDFP2YMUWBPLRGLCKTA5CNFSM4LDHLQXKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEOEG2OQ#issuecomment-596143418,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACBML7W43RCIHT6I7SQGTYTRGLCKTANCNFSM4LDHLQXA
.

I expected required_if to produce an invalid observer flag if the source of the if was changed and there wasn't a value in the target. Stephantabor's solution worked for me. I supplemented the required_if source with a watcher that manually called validate().

See this CodePen for a working example.

https://codepen.io/walkerca/pen/zYGPXmp

Can anyone give a working example to trigger the observer for when using TypeScript and the Vue component is setup like this:

<template>
  <validation-observer ref="validationObserver" v-slot="validationObserver">
      <form>
        <div class="top">
          <validation-provider v-slot="provider" name="email" rules="email">
            <label for="email">email (required)</label>
            <input name="email" type="email" v-model="email"/>
            <pre>{{ provider.errors[0] }}</pre>
          </validation-provider>
        </div>
        <div>
          <validation-provider v-slot="provider" name="foo" rules="required_if:email">
            <label for="foo">Required If email is not blank</label>
            <input name="foo" v-model="foo" :disabled="!email"/>
            <pre>{{ provider.errors[0] }}</pre>
            <p>full validation</p>
            <pre>{{ pretty(provider) }}</pre>
          </validation-provider>
        </div>
      </form>
  </validation-observer>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { ValidationObserver, ValidationProvider } from 'vee-validate'

@Component({
  components: {
    ValidationObserver,
    ValidationProvider
  },
  name: 'App'
})
export default class extends Vue {
}

The watch example from above doesn't compile with this style of Vue component. It complains that "Property 'validate' does not exist on type 'Vue | Element | Vue[] | Element[]'.   Property 'validate' does not exist on type 'Vue'."

I can't cast it to anything because there's no type exported for ValidationObserver, just the const instance.

@efenderbosch

This is how i do it, not sure if there's a better way

<template>
  <validation-observer ref="observer" />
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { ValidationObserver, ValidationProvider } from 'vee-validate'

@Component({
  components: {
    ValidationObserver,
    ValidationProvider
  },
  name: 'App'
})
export default class extends Vue {
  $refs!: {
    observer: InstanceType<typeof ValidationObserver>;
  };
}
</script>

Thanks @stephantabor, that got me really close to getting it working.

Finally got it triggering as I wanted with this:

  @Ref('validationObserver')
  private validationObserver!: InstanceType<typeof ValidationObserver>

  @Watch('path.to.watched.prop')
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  async onPathToWatchedPropChange (val: string, oldVal: string): Promise<void> {
    await this.validationObserver.validate({ silent: false })
    return Promise.resolve()
  }
Was this page helpful?
0 / 5 - 0 ratings