The New Way to Build with AI! Introducing ReUI — the developer platform for agentic UI with shadcn/ui
Browse ReUI Pro

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>
Text formatting options
Submit
Click any option to insert into your comment. Select text first to wrap it.
  • **text** to make things bold
  • *text* to emphasize
  • ### Heading to make headings
  • [link text](url) for links
  • ![alt text](image-url) to paste in an image
  • - item to make a list
  • 1. item to make an ordered list
  • > quote to quote somebody
  • `code` for single line of code
  • ```js ... ``` for JS code block
  • ```html ... ``` for HTML code block
  • ```scss ... ``` for SCSS code block
  • ```php ... ``` for PHP code block
  • --- for a horizontal rule
  • happy  :)
  • shocked  :|
  • sad  :(

Replies (4)

 
Deleted comment

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


<pre> <!--STEP 2 START --> <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+key"> <div class="fv-row mb-10" > <label class="form-label required" :for="field.name+key">{{ field.label }}</label> <Field :as="field.as" : :name="field.name+key" :class="field.class" :key="key" v-mask="field.mask ? field.mask : false" /> <ErrorMessage :name="field.name+key" 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" > Add Location </button> </div> </div> <!--end::Wrapper--> </template> <script lang="ts"> import { defineComponent,computed } from "vue"; import { Field, ErrorMessage } from "vee-validate"; import {mask} from 'vue-the-mask' import { useStore } from "vuex"; import { useRouter } from "vue-router"; import { Actions } from "@/store/enums/StoreEnums"; import { Mutations } from "@/store/enums/StoreEnums"; import * as Yup from 'yup'; export default defineComponent({ name: "step-2", components: { Field, ErrorMessage, }, directives: { mask: (el, binding) => { if (!binding.value) { return; } mask(el, binding); } }, setup () { }, data: function () { const count = 1; const formSchema = { fields: [ { label: 'Shipper Contact Person', name: `shipper_contact_person`, id: `shipper_contact_person`, as: 'input', class: 'form-control form-control-lg form-control-solid', }, { id: `shipper_phone_number`, label: 'Shipper Phone Number', name: 'shipper_phone_number', class: 'form-control form-control-lg form-control-solid', as: 'input', mask:"####-#######", }, { id: `shipper_email`, label: 'Shipper Email Address', name: `shipper_email`, class: 'form-control form-control-lg form-control-solid', as: 'input', }, { id: `shipper_city`, label: 'Shipper City', name: `shipper_city`, class: 'form-control form-control-lg form-control-solid', as: 'input', }, { id: `shipper_address`, label: 'Shipper Address', name: `shipper_address`, class: 'form-control form-control-lg form-control-solid', as: 'textarea', }, { id: `shipper_brand_name`, label: 'Brand Name', name: `shipper_brand_name`, class: 'form-control form-control-lg form-control-solid', as: 'input', }, { id: `shipper_cnic`, label: 'CNIC#', name: `shipper_cnic`, class: 'form-control form-control-lg form-control-solid', as: 'input', mask : "#####-#######-#" }, ], }; return { count, values: {}, formSchema, } }, methods: { add: function(){ this.count++; }, remove: function () { this.count--; }, submit: function(){ // for (var key of Object.keys(this.values)) { // console.log(key + " -> " + this.values[key]) // } } } }); </script> <!--STEP 2 END --> <!--HORIZONTAL VUE START --> <template> <!--begin::Card--> <div class="separator my-2"></div> <div class="mb-10 text-center"> <!--begin::Title--> <h1 class="text-dark mb-3">Sign Up</h1> <!--end::Title--> <!--begin::Link--> <div class="text-gray-400 fw-semobold fs-4"> Already have an account? <router-link to="/sign-in" class="link-primary fw-bold"> Sign in here </router-link> </div> <!--end::Link--> </div> <div class="card"> <!--begin::Card body--> <div class="card-body"> <!--begin::Stepper--> <div class="stepper stepper-links d-flex flex-column"

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

Text formatting options
Submit
Click any option to insert into your comment. Select text first to wrap it.
  • **text** to make things bold
  • *text* to emphasize
  • ### Heading to make headings
  • [link text](url) for links
  • ![alt text](image-url) to paste in an image
  • - item to make a list
  • 1. item to make an ordered list
  • > quote to quote somebody
  • `code` for single line of code
  • ```js ... ``` for JS code block
  • ```html ... ``` for HTML code block
  • ```scss ... ``` for SCSS code block
  • ```php ... ``` for PHP code block
  • --- for a horizontal rule
  • happy  :)
  • shocked  :|
  • sad  :(
Text formatting options
Submit
Click any option to insert into your comment. Select text first to wrap it.
  • **text** to make things bold
  • *text* to emphasize
  • ### Heading to make headings
  • [link text](url) for links
  • ![alt text](image-url) to paste in an image
  • - item to make a list
  • 1. item to make an ordered list
  • > quote to quote somebody
  • `code` for single line of code
  • ```js ... ``` for JS code block
  • ```html ... ``` for HTML code block
  • ```scss ... ``` for SCSS code block
  • ```php ... ``` for PHP code block
  • --- for a horizontal rule
  • happy  :)
  • shocked  :|
  • sad  :(
buy metronic keenthemes mega bundle

ReUI

Open-source React components, blocks and templates built on shadcn/ui and Tailwind CSS by Keenthemes.