Search code examples
vue.jstailwind-cssvuelidate

Vuelidate & Tailwind: Why am I always seeing invalid errors?


For the life of me I cannot seem to understand why I am always seeing the validation error(s). The logic is working great, it seems to all be in my :class binding(s) that I've got it all wrong. I know I'm going to feel really silly when I get this figured out, but after countless tutorials that I feel like I've literally copy/paste from, I'm still in the same boat.

Here is my template for email. The password input is the same...

<div class="relative">
    <label for="email" class="sr-only block text-sm font-medium leading-5 text-gray-700">
        Email address
    </label>
    <input type="email"
        id="email"
        v-model.trim="$v.user.email.$model"
        :class="{ 'border-red-500': !$v.user.email.required}"
        placeholder="Email"
        class="mt-1 placeholder-gray-400 shadow appearance-none border rounded w-full py-3 px-3 text-gray-700 leading-tight transition duration-150 ease-in-out sm:text-sm sm:leading-5 focus:outline-none focus:border-gray-400 focus:shadow-outline-gray"
    />
    <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none" 
        v-if="!$v.user.email.required">
              <svg
                  class="h-5 w-5 text-red-500"
                  fill="currentColor"
                  viewBox="0 0 20 20"
              >
                <path
                    fill-rule="evenodd"
                    d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
                    clip-rule="evenodd"
                />
              </svg>
            </div>
        </div>
    <div>
    <p class="mt-2 text-sm text-red-600" v-if="!$v.user.email.required">
        Email is required
    </p>
    <p class="mt-2 text-sm text-red-600" v-if="!$v.user.email.email">
        Please use a valid email address
    </p>
</div>

This is what my script block looks like:

data: () => ({
    errors: false,
    user: {
      email: "",
      password: "",
    },
  }),


validations: {
    user: {
      email: { required, email },
      password: { required },
    },
  },

methods: {
    async handleSignIn() {
      this.$v.user.$touch();
      this.empty = !this.$v.user.$anyDirty;
      this.errors = this.$v.user.$anyError;

      if (this.$v.$invalid) {
        this.errors = true;
      } else {
        try {
            ...
        }
      }
   }

As I enter a valid email and/or password, the validation errors go away. If I try to submit with invalid data, the validator is working properly. With a valid email/password, I'm able to successfully submit the form.

When the page first loads, here is what my form looks like. How can I correctly render the form to only show the errors if a field is invalid?

Thank you for any suggestions!

enter image description here


Solution

  • Try to add the $v.user.email.$error condition to the border class binding, the icon and the error message :

    <div id="app">
      <div class="relative">
        <label for="email" class="sr-only block text-sm font-medium leading-5 text-gray-700">
          Email address
        </label>
        <input type="email" id="email" v-model.trim="$v.user.email.$model" :class="{ 'border-red-500': $v.user.email.$error}" placeholder="Email" class="mt-1 placeholder-gray-400 shadow appearance-none border rounded w-full py-3 px-3 text-gray-700 leading-tight transition duration-150 ease-in-out sm:text-sm sm:leading-5 focus:outline-none focus:border-gray-400 focus:shadow-outline-gray" />
        <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none" v-if="!$v.user.email.required">
          <svg v-if="$v.user.email.$error" class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
            <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
          </svg>
        </div>
      </div>
      <div>
        <p class="mt-2 text-sm text-red-600" v-if="$v.user.email.$error">
          Email is required
        </p>
        <p class="mt-2 text-sm text-red-600" v-if="!$v.user.email.email">
          Please use a valid email address
        </p>
        <button class="rounded w-full flex justify-center text-gray-100 bg-purple-700 hover:bg-purple-800 px-6 py-2 flex items-center">
          Submit
        </button>
      </div>
    </div>
    

    LIVE DEMO