Form Validation Fix

User
<script>
import { ref,inject,onMounted } from "vue";
import Google from '@/assets/images/auth/social-google.svg';
import { useAuthStore } from '@/stores/auth';
import { useLoadingStore } from '@/stores/loading';
import { useRouter } from 'vue-router';
import { Form } from 'vee-validate';
import publicApi from '@/publicApi';
const apiUrl = inject('apiUrl');
const loadingStore = useLoadingStore();
const authStore = useAuthStore();
const router = useRouter();
const alertMessage=ref("");
const alertColor=ref("");
const checkbox = ref(false);
const valid = ref(false);
const show1 = ref(false);
//const logform = ref();
const password = ref('');
const username = ref('');
const passwordRules = ref([
  (v: string) => !!v || 'Password is required',
  (v: string) => (v && v.length <= 10) || 'Password must be less than 10 characters'
]);
const emailRules = ref([(v: string) => !!v || 'E-mail is required', (v: string) => /.+@.+..+/.test(v) || 'E-mail must be valid']);

/* eslint-disable @typescript-eslint/no-explicit-any */
const submit = async () => {
    loadingStore.setLoading(true);
    alertMessage.value = "";
    alertColor.value = "";
    try {
    const response = await publicApi.post(`${apiUrl}/login`, {
      email: username.value,
      password: password.value
    });
    
   console.log(response);
    if (response.data.success) {
      alertMessage.value = "Login successful!";
      alertColor.value = 'success';
      authStore.setUser(response.data.user, response.data.token);
      router.push('/dashboard');
    } else {
      console.log(response.data);
      alertMessage.value = response.data.message;
      alertColor.value = 'error';
      console.error("Login failed:", response.data.message);
    }
  } catch (error: any) {
   console.log(error);
  
    alertMessage.value =error.response?.data.message;
    alertColor.value = 'error';
    console.error("Error during login:", error.response?.data.message || error.message);
  } finally {
    loadingStore.setLoading(false);
  }
  }
</script>

Sign in with Google

OR

Sign in with Email address

Forgot password?

Sign In

{{ errors.apiError }}

Don't Have an account?

<style>
.custom-devider {
  border-color: rgba(0, 0, 0, 0.08) !important;
}
.googleBtn {
  border-color: rgba(0, 0, 0, 0.08);
  margin: 30px 0 20px 0;
}
.outlinedInput .v-field {
  border: 1px solid rgba(0, 0, 0, 0.08);
  box-shadow: none;
}
.orbtn {
  padding: 2px 40px;
  border-color: rgba(0, 0, 0, 0.08);
  margin: 20px 15px;
}
.pwdInput {
  position: relative;
  .v-input__append {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
  }
}
.loginForm {
  .v-text-field .v-field--active input {
    font-weight: 500;
  }
}
</style>

Uncaught (in promise) TypeError: e.preventDefault is not a function
at prevent (chunk-U3LI7FBV.js?v=63b73135:12141:21)
at cache..cache. (chunk-U3LI7FBV.js?v=63b73135:12158:20)
at vee-validate.js?v=63b73135:2246:20
on click sign in

Assistant
The error `TypeError: e.preventDefault is not a function` suggests that the `submit` function is being called incorrectly, or the event parameter is not being passed properly.

### Possible Issues & Fixes:

#### 1. **Incorrect Usage of `@submit.prevent`**
You're using VeeValidate's “ component with `@submit.prevent="submit"`. However, VeeValidate handles form submission internally, so using `.prevent` might not be necessary.

โœ… **Fix: Remove `.prevent` from `@submit`**

<Form @submit="submit" class="mt-7 loginForm" v-slot="{ errors, isSubmitting }">

#### 2. **VeeValidate's Submission Handling**
The `submit` function should accept `values` from VeeValidate, instead of relying on Vue's `ref` values directly.

โœ… **Fix: Update `submit` function to use `values`**
Modify the `submit` function to accept `values` from VeeValidate:

const submit = async (values: { email: string; password: string }) => {
    loadingStore.setLoading(true);
    alertMessage.value = "";
    alertColor.value = "";
    try {
        const response = await publicApi.post(`${apiUrl}/login`, {
            email: values.email,  // Use values from VeeValidate
            password: values.password
        });

        console.log(response);
        if (response.data.success) {
            alertMessage.value = "Login successful!";
            alertColor.value = 'success';
            authStore.setUser(response.data.user, response.data.token);
            router.push('/dashboard');
        } else {
            alertMessage.value = response.data.message;
            alertColor.value = 'error';
            console.error("Login failed:", response.data.message);
        }
    } catch (error: any) {
        alertMessage.value = error.response?.data.message;
        alertColor.value = 'error';
        console.error("Error during login:", error.response?.data.message || error.message);
    } finally {
        loadingStore.setLoading(false);
    }
};

#### 3. **Update the “ Component**
Pass field values properly via `v-slot="{ values }"` in “:

<Form @submit="submit" class="mt-7 loginForm" v-slot="{ errors, isSubmitting, values }">
    <v-text-field
        v-model="values.email"
        :rules="emailRules"
        label="Email Address / Username"
        class="mt-4 mb-8"
        required
        density="comfortable"
        hide-details="auto"
        variant="outlined"
        color="primary"
    ></v-text-field>

    <v-text-field
        v-model="values.password"
        :rules="passwordRules"
        label="Password"
        required
        density="comfortable"
        variant="outlined"
        color="primary"
        hide-details="auto"
        :append-icon="show1 ? '$eye' : '$eyeOff'"
        :type="show1 ? 'text' : 'password'"
        @click:append="show1 = !show1"
        class="pwdInput"
    ></v-text-field>
  
    <v-btn color="secondary" :loading="isSubmitting" block class="mt-2" variant="flat" size="large" type="submit">
      Sign In
    </v-btn>
</Form>

#### 4. **Use `valid` Correctly**
The `valid` ref is currently unused, but if you want to disable the submit button when the form is invalid, update it dynamically:

<v-btn color="secondary" :loading="isSubmitting" block class="mt-2" variant="flat" size="large" 
  :disabled="Object.keys(errors).length > 0" type="submit">
  Sign In
</v-btn>

### Summary of Fixes:
– **Remove `.prevent`** from `@submit.prevent="submit"`.
– **Modify `submit` function** to accept `values` from VeeValidate.
– **Update “ to use `v-slot="{ values }"`**.
– **Fix button disable logic** using `Object.keys(errors).length > 0`.

Try these fixes, and your issue should be resolved! ๐Ÿš€

User
okay but now blank form submit
Assistant
If your form is submitting even when the fields are blank, it means that the validation rules are not being enforced correctly. Let's fix this by ensuring that **VeeValidate's validation system** is properly integrated.

### ๐Ÿ”ง Fixes:

1. **Ensure Fields are Registered with `Field` from VeeValidate**
– Instead of using `v-model`, use “ components from VeeValidate to register fields properly.
– This ensures validation is correctly applied before submission.

2. **Ensure `errors` Object is Used Correctly**
– Use `errors.email` and `errors.password` to display validation messages and disable the submit button accordingly.

### โœ… **Updated Code with Proper Validation Handling**

#### **Step 1: Import Required Components**
Modify your script section to include `Field` from VeeValidate:

<script setup lang="ts">
import { ref, inject } from "vue";
import { Form, Field } from 'vee-validate';
import * as yup from 'yup';
import { useAuthStore } from '@/stores/auth';
import { useLoadingStore } from '@/stores/loading';
import { useRouter } from 'vue-router';
import publicApi from '@/publicApi';

const apiUrl = inject('apiUrl');
const loadingStore = useLoadingStore();
const authStore = useAuthStore();
const router = useRouter();
const alertMessage = ref("");
const alertColor = ref("");

/* Validation Schema using Yup */
const validationSchema = yup.object({
  email: yup.string().required('E-mail is required').email('E-mail must be valid'),
  password: yup.string().required('Password is required').max(10, 'Password must be less than 10 characters'),
});

/* Submit Function */
const submit = async (values: { email: string; password: string }) => {
    loadingStore.setLoading(true);
    alertMessage.value = "";
    alertColor.value = "";
    try {
        const response = await publicApi.post(`${apiUrl}/login`, {
            email: values.email,  // Use values from VeeValidate
            password: values.password
        });

        if (response.data.success) {
            alertMessage.value = "Login successful!";
            alertColor.value = 'success';
            authStore.setUser(response.data.user, response.data.token);
            router.push('/dashboard');
        } else {
            alertMessage.value = response.data.message;
            alertColor.value = 'error';
        }
    } catch (error: any) {
        alertMessage.value = error.response?.data.message || "Login failed.";
        alertColor.value = 'error';
    } finally {
        loadingStore.setLoading(false);
    }
};
</script>

#### **Step 2: Update Your “ in the Template**
Now, update your “ to properly use `Field` components from VeeValidate.

<template>
  <v-btn block color="primary" variant="outlined" class="text-lightText googleBtn">
    <img :src="Google" alt="google" />
    <span class="ml-2">Sign in with Google</span>
  </v-btn>

  <v-row>
    <v-col class="d-flex align-center">
      <v-divider class="custom-devider" />
      <v-btn variant="outlined" class="orbtn" rounded="md" size="small">OR</v-btn>
      <v-divider class="custom-devider" />
    </v-col>
  </v-row>

  <h5 class="text-h5 text-center my-4 mb-8">Sign in with Email address</h5>

  <Form @submit="submit" :validation-schema="validationSchema" v-slot="{ errors, isSubmitting }" class="mt-7 loginForm">
    <!-- Email Input -->
    <Field name="email" v-slot="{ field }">
      <v-text-field
        v-bind="field"
        label="Email Address / Username"
        class="mt-4 mb-8"
        required
        density="comfortable"
        hide-details="auto"
        variant="outlined"
        color="primary"
        :error-messages="errors.email"
      ></v-text-field>
    </Field>

    <!-- Password Input -->
    <Field name="password" v-slot="{ field }">
      <v-text-field
        v-bind="field"
        label="Password"
        required
        density="comfortable"
        variant="outlined"
        color="primary"
        hide-details="auto"
        :append-icon="show1 ? '$eye' : '$eyeOff'"
        :type="show1 ? 'text' : 'password'"
        @click:append="show1 = !show1"
        class="pwdInput"
        :error-messages="errors.password"
      ></v-text-field>
    </Field>

    <!-- Remember Me Checkbox -->
    <div class="d-sm-flex align-center mt-2 mb-7 mb-sm-0">
      <v-checkbox v-model="checkbox" label="Remember me?" color="primary" class="ms-n2" hide-details></v-checkbox>
      <div class="ml-auto">
        <a href="javascript:void(0)" class="text-primary text-decoration-none">Forgot password?</a>
      </div>
    </div>

    <!-- Submit Button -->
    <v-btn color="secondary" :loading="isSubmitting" block class="mt-2" variant="flat" size="large"
      :disabled="Object.keys(errors).length > 0" type="submit">
      Sign In
    </v-btn>

    <!-- Alert Messages -->
    <v-alert v-if="alertMessage" :color="alertColor" class="mt-2">
      {{ alertMessage }}
    </v-alert>
  </Form>

  <div class="mt-5 text-right">
    <v-divider />
    <v-btn variant="plain" to="/register" class="mt-2 text-capitalize mr-n2">Don't Have an account?</v-btn>
  </div>
</template>

### โœ… **Why This Works**
โœ” Uses `Field` components from VeeValidate to manage input values properly.
โœ” Uses `yup` for schema validation instead of manual rules.
โœ” Prevents submission when there are validation errors.
โœ” Displays error messages dynamically under each field.
โœ” Uses `Object.keys(errors).length > 0` to disable the **Sign In** button if validation fails.

๐Ÿš€ **Now, your form will NOT submit when blank fields are entered, and validation will work correctly!** Let me know if you need further refinements! ๐ŸŽฏ

Leave a Comment

Your email address will not be published. Required fields are marked *