Dynamic Validation Vue Vee Validate
Hello i want to validate dynamic fields using vee validate, Fields having the same name. For Example
<pre> <template> <!--begin::Wrapper--> <div class="row"> <div v-for="key in count" :key="key"> <div class="col-md-3" v-for="field in formSchema.fields" :key="field.name"> <div class="fv-row mb-10" > <label class="form-label required" :for="field.name">{{ field.label }}</label> <Field :as="field.as" :id="field.id+`[${key}]`" :name="field.name" :class="field.class" :key="key" v-mask="field.mask ? field.mask : false" /> <ErrorMessage :name="field.name" class="fv-plugins-message-container invalid-feedback" ></ErrorMessage> </div> </div> </div> <div class="row"> <button type="button" class="btn btn-lg btn-success me-3" @click="add" id="add_more_fields"> Add Location </button> </div> </div> <!--end::Wrapper--> </template> </pre>Replies (4)
I have attached (step 2) and the (horizontal) vue page, is there way to validate all the dynamic fields inside the step2, I feel like Yup Object is ignoring dynamic fields
Hi Syed,
I think "Form Generator" page describes how you can validate dynamically rendered fields. See
Regards,
Lauris Stepanovs,
Keenthemes Support Team
ref="horizontalWizardRef"
<!--begin::Nav--> <div class="stepper-nav py-5 mt-5"> <!--begin::Step 1--> <div class="stepper-item current" data-kt-stepper-element="nav"> <h3 class="stepper-title">Profile Information</h3> </div> <!--end::Step 1--> <!--begin::Step 2--> <div class="stepper-item" data-kt-stepper-element="nav"> <h3 class="stepper-title">Shipping Information</h3> </div> <!--end::Step 2--> <!--begin::Step 3--> <div class="stepper-item" data-kt-stepper-element="nav"> <h3 class="stepper-title">Banking Information</h3> </div> <!--end::Step 3--> <!--begin::Step 4--> <div class="stepper-item" data-kt-stepper-element="nav"> <h3 class="stepper-title">Documents & Legal</h3> </div> <!--end::Step 4--> <!--begin::Step 5--> <div class="stepper-item" data-kt-stepper-element="nav"> <h3 class="stepper-title">Login Information</h3> </div> <!--end::Step 5--> </div> <!--end::Nav--> <!--begin::Form--> <form class="mx-auto mw-600px w-100 pt-15 pb-10" novalidate="novalidate"
@submit="handleStep"
<!--begin::Step 1--> <div class="current" data-kt-stepper-element="content" > <Step1></Step1> </div> <!--end::Step 1--> <!--begin::Step 2--> <div data-kt-stepper-element="content" > <Step2></Step2> </div> <!--end::Step 2--> <!--begin::Step 3--> <div data-kt-stepper-element="content" > <Step3></Step3> </div> <!--end::Step 3--> <!--begin::Step 4--> <div data-kt-stepper-element="content" > <Step4></Step4> </div> <!--end::Step 4--> <!--begin::Step 5--> <div data-kt-stepper-element="content" > <Step5></Step5> </div> <!--end::Step 5--> <!--begin::Actions--> <div class="d-flex flex-stack pt-15"> <!--begin::Wrapper--> <div class="mr-2"> <button type="button" class="btn btn-lg btn-light-primary me-3" data-kt-stepper-action="previous" @click="previousStep" > <span class="svg-icon svg-icon-4 me-1"> <inline-svg src="media/icons/duotune/arrows/arr063.svg" /> </span> Back </button> </div> <!--end::Wrapper--> <!--begin::Wrapper--> <div> <button type="button" class="btn btn-lg btn-primary me-3" data-kt-stepper-action="submit" v-if="currentStepIndex === totalSteps - 1" @click="formSubmit()" > <span class="indicator-label"> Submit <span class="svg-icon svg-icon-3 ms-2 me-0"> <inline-svg src="media/icons/duotune/arrows/arr064.svg" /> </span> </span> <span class="indicator-progress"> Please wait... <span class="spinner-border spinner-border-sm align-middle ms-2" ></span> </span> </button> <button v-else type="submit" class="btn btn-lg btn-primary"> Continue <span class="svg-icon svg-icon-4 ms-1 me-0"> <inline-svg src="media/icons/duotune/arrows/arr064.svg" /> </span> </button> </div> <!--end::Wrapper--> </div> <!--end::Actions--> </form> <!--end::Form--> </div> <!--end::Stepper--> </div> <!--end::Card body--> </div> <!--end::Card--> </template> <script lang="ts"> import { computed, defineComponent, onMounted, ref } from "vue"; import { StepperComponent } from "@/assets/ts/components"; import { useForm } from "vee-validate"; import Swal from "sweetalert2/dist/sweetalert2.min.js"; import * as Yup from "yup"; import Step1 from "@/components/wizard/steps/Step1.vue"; import Step2 from "@/components/wizard/steps/Step2.vue"; import Step3 from "@/components/wizard/steps/Step3.vue"; import Step4 from "@/components/wizard/steps/Step4.vue"; import Step5 from "@/components/wizard/steps/Step5.vue"; interface IStep1 { contact_name: string; contact_person: string; phone_no : string; phone_no2 : string; address : string; cnic : string city : string ntn_no : string url : string account_type : string reference_type : string sale_person : string } interface IStep2 { shipper_contact_person : string; shipper_phone_number : string; shipper_email : string; shipper_city : string; shipper_address : string; shipper_brand_name : string; shipper_cnic : string; } interface IStep3 { businessName: string; businessDescriptor: string; businessType: string; businessDescription: string; businessEmail: string; } interface IStep4 { nameOnCard: string; cardNumber: string; cardExpiryMonth: string; cardExpiryYear: string; cardCvv: string; saveCard: string; } interface CreateAccount extends IStep1, IStep2, IStep3, IStep4 {} export default defineComponent({ name: "kt-horizontal-wizard", components: { Step1, Step2, Step3, Step4, Step5, }, setup() { const _stepperObj = ref<StepperComponent | null>(null); const horizontalWizardRef = ref<HTMLElement | null>(null); const currentStepIndex = ref(0); const formData = ref<CreateAccount>({ contact_name: "Contact Name", contact_person: "Contact Person", phone_no: "Phone Number", phone_no2: "Phone Number 2", address: "Address", city : "City", cnic : "CNIC#", ntn_no : "NTN #", url : "URL", account_type : "Account Type", reference_type : "Reference No#", sale_person : "Sale Person", shipper_contact_person : "Shipper Contact Person", shipper_phone_number : "Shipper Phone Number", shipper_email : "Shipper Email", shipper_city : "Shipper City", shipper_address : "Shipper Address", shipper_brand_name : "Shipper Brand Name", shipper_cnic : "Shipper CNIC", businessName: "Keenthemes Inc.", businessDescriptor: "KEENTHEMES", businessType: "1", businessDescription: "", businessEmail: "corp@support.com", nameOnCard: "Max Doe", cardNumber: "4111 1111 1111 1111", cardExpiryMonth: "1", cardExpiryYear: "2", cardCvv: "123", saveCard: "1", }); onMounted(() => { _stepperObj.value = StepperComponent.createInsance( horizontalWizardRef.value as HTMLElement ); }); const createAccountSchema = [ Yup.object({ contact_name: Yup.string().required(), contact_person: Yup.string().required(), phone_no: Yup.string().required(), phone_no2: Yup.string().required(), address: Yup.string().required(), city: Yup.string().required(), cnic: Yup.string().required().min(15), ntn_no : Yup.string().required(), url : Yup.string().required(), account_type : Yup.string().required(), reference_type : Yup.string().required(), sale_person : Yup.string().required(), }), Yup.object({ shipper_contact_person : Yup.string().required(), shipper_phone_number : Yup.string().required(), shipper_email : Yup.string().required(), shipper_city : Yup.string(), shipper_address : Yup.string(), shipper_brand_name : Yup.string() , shipper_cnic : Yup.string(), }), Yup.object({ businessName: Yup.string().required().label("Business Name"), businessDescriptor: Yup.string() .required() .label("Shortened Descriptor"), businessType: Yup.string().required().label("Corporation Type"), businessEmail: Yup.string().required().label("Contact Email"), }), Yup.object({ nameOnCard: Yup.string().required().label("Name On Card"), cardNumber: Yup.string().required().label("Card Number"), cardExpiryMonth: Yup.string().required().label("Expiration Month"), cardExpiryYear: Yup.string().required().label("Expiration Year"), cardCvv: Yup.string().required().label("CVV"), }), ]; const currentSchema = computed(() => { return createAccountSchema[currentStepIndex.value]; }); const { resetForm, handleSubmit } = useForm< IStep1 | IStep2 | IStep3 | IStep4 >({ validationSchema: currentSchema, }); const totalSteps = computed(() => { if (!_stepperObj.value) { return; } return _stepperObj.value.totatStepsNumber; }); const handleStep = handleSubmit((values) => { // resetForm({ // values: { // ...formData.value, // }, // }); console.log(formData.value); for (const item in values) { // eslint-disable-next-line no-prototype-builtins if (values.hasOwnProperty(item)) { if (values[item]) { formData.value[item] = values[item]; } } } currentStepIndex.value++; if (!_stepperObj.value) { return; } _stepperObj.value.goNext(); }); const previousStep = () => { if (!_stepperObj.value) { return; } currentStepIndex.value--; _stepperObj.value.goPrev(); }; const formSubmit = () => { Swal.fire({ text: "All is cool! Now you submit this form", icon: "success", buttonsStyling: false, confirmButtonText: "Ok, got it!", customClass: { confirmButton: "btn fw-semobold btn-light-primary", }, }).then(() => { window.location.reload(); }); }; return { horizontalWizardRef, previousStep, handleStep, formSubmit, totalSteps, currentStepIndex, }; }, }); </script> <!--HORIZONTAL VUE END--> </pre>
Hi Syed,
The name attribute value should be unique for each field.
You can use your key variable to make name value unique and then use the name for validation.
<pre> :name="`${field.name}-${key}`" </pre>Regards, Lauris Stepanovs, Keenthemes Support Team