Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form: v-slot="$form" doesn't handle nested array of objects #6924

Closed
jarobober opened this issue Dec 4, 2024 · 11 comments
Closed

Form: v-slot="$form" doesn't handle nested array of objects #6924

jarobober opened this issue Dec 4, 2024 · 11 comments
Assignees
Labels
Type: Enhancement Issue contains an enhancement related to a specific component. Additional functionality has been add
Milestone

Comments

@jarobober
Copy link

Describe the bug

Couldn't handled properly form data which is object with nested array of objects. Looks like v-slot="$form" doesn't support nested arrays.

That's our form data:
const data = ref({ username: '', emails: [ { title: '', address: '', }, { title: '', address: '', }, ], });

That's what v-slot="$form" returns:
{ "valid": true, "username": { "value": "", "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] }, "title": { "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] }, "address": { "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] } }

Due to that we can't validate it using yup. We are currently introducing PrimeVue into new version of our app so handling nested arrays and objects in forms would be needed.

If there is an alternative way to achieve this, any guidence would be greatly appreciated.
Best regards!

Reproducer

https://stackblitz.com/edit/pgshym?file=src%2FApp.vue

PrimeVue version

4.2.4

Vue version

4.x

Language

TypeScript

Build / Runtime

Vite

Browser(s)

Chrome 131.0

Steps to reproduce the behavior

No response

Expected behavior

No response

@jarobober jarobober added the Status: Needs Triage Issue will be reviewed by Core Team and a relevant label will be added as soon as possible label Dec 4, 2024
@saidtaylan
Copy link

Yes. I have tried way @jarobober but i cannot succeed as well. I want to add additional objects dynamically to array and validate it. But i cannot iterate over the loop.

@Mihaszki
Copy link

Mihaszki commented Dec 9, 2024

Yes. Same problem as @jarobober
This is quite important for more complex forms with many inputs.

@arikanaydin
Copy link

arikanaydin commented Dec 9, 2024

Yes, Same problem as @jarobober
`const resolver = ref(
yupResolver(
yup.object().shape({
sourceName: yup.string().required('Source name is required.'),
locales: yup
.array()
.of(
yup.object().shape({
name: yup.string().required('Name is required.'),
})
)
.required('Locales are required.')
.test('all-names-filled', 'All locales must have a name.', (value) => {
return value?.every((locale) => locale.name.trim() !== '');
}),
})
)
);
const initialValues = reactive({
sourceName: "",
locales: languages.value.map((lang) => ({ name: "", code: lang.code })),
})

  <div v-for="(lang, index) in initialValues.locales.sort((a,b) => (a.code > b.code) ? 1 : ((b.code > a.code) ? -1 : 0))" :key="lang.code" class="col-span-3">
    <FloatLabel variant="in">
      <InputText
          :name="`locales[${index}].name`"
          :id="`${lang.code}_name`"
          class="w-full"
          v-model="lang.name"
      />
      <label :for="`${lang.code}_name`">{{ lang.code }} Name </label>
    </FloatLabel>
    <Message
        v-if="($form as any).locales && ($form as any).locales[index]?.name?.invalid"
        severity="error"
        size="small"
        variant="simple"
    >
      {{ ($form as any).locales[index]?.name?.error?.message || 'Invalid value' }}
    </Message>


  </div>

`

@tugcekucukoglu tugcekucukoglu added Status: Pending Review Issue or pull request is being reviewed by Core Team and removed Status: Needs Triage Issue will be reviewed by Core Team and a relevant label will be added as soon as possible labels Dec 10, 2024
@tugcekucukoglu tugcekucukoglu added this to the 4.3.0 milestone Dec 10, 2024
@github-project-automation github-project-automation bot moved this to Review in PrimeVue Dec 10, 2024
@mertsincan mertsincan modified the milestones: 4.3.1, 4.3.0 Jan 6, 2025
@mertsincan mertsincan self-assigned this Jan 6, 2025
@gimler
Copy link

gimler commented Jan 8, 2025

@Matheusfrej
Copy link

Hi, having the same problem! Im using zod for validation. Can't find a way have nested array of objects.

@mertsincan
Copy link
Member

mertsincan commented Jan 12, 2025

Fixed in 536d21c

You can update the name prop using index.

Exp;

<Form v-slot="$form" :initialValues="data" :resolver="resolver" @submit="onFormSubmit" class="flex flex-col gap-4 w-full">
    Data in form: {{ $form }}
    <div class="flex flex-col gap-1">
        <InputText v-model="data.username" name="username" type="text" placeholder="Username" fluid />
        <Message v-if="$form.username?.invalid" severity="error" size="small" variant="simple">{{ $form.username.error.message }}</Message>
    </div>
    Email Addresses:
    <div v-for="(item, index) in data.emails" class="flex flex-col gap-1">
        Address {{ index + 1 }}
        <InputText v-model="data.emails[index].title" :name="`emails[${index}].title`" type="text" placeholder="Email Title" fluid />
        <Message v-if="$form.emails?.[index]?.title?.invalid" severity="error" size="small" variant="simple">{{ $form.emails[index].title.error.message }}</Message>
  
        <InputText v-model="data.emails[index].address" :name="`emails[${index}].address`" type="text" placeholder="Email Address" fluid />
        <Message v-if="$form.emails?.[index]?.address?.invalid" severity="error" size="small" variant="simple">{{ $form.emails[index].address.error.message }}</Message>
    </div>
    <Button type="submit" severity="secondary" label="Submit" />
 </Form>
...
const data = ref({
    username: '',
    emails: [
        {
            title: '',
            address: ''
        },
        {
            title: '',
            address: ''
        }
    ]
});

const resolver = ref(
    yupResolver(
        yup.object().shape({
            username: yup.string().required('Username is required via Yup.'),
            emails: yup.array(
                yup.object({
                    title: yup.string().required('Email title is required via Yup.'),
                    address: yup.string().required('Email address is required via Yup.')
                })
            )
        })
    )
);
...

@github-project-automation github-project-automation bot moved this from Review to Done in PrimeVue Jan 12, 2025
@mertsincan mertsincan added Type: Enhancement Issue contains an enhancement related to a specific component. Additional functionality has been add and removed Status: Pending Review Issue or pull request is being reviewed by Core Team labels Jan 15, 2025
@arikanaydin
Copy link

arikanaydin commented Jan 27, 2025

Fixed in 536d21c

You can update the name prop using index.

Exp;

Data in form: {{ $form }}
{{ $form.username.error.message }}
Email Addresses:
Address {{ index + 1 }} {{ $form.emails[index].title.error.message }}
    <InputText v-model="data.emails[index].address" :name="`emails[${index}].address`" type="text" placeholder="Email Address" fluid />
    <Message v-if="$form.emails?.[index]?.address?.invalid" severity="error" size="small" variant="simple">{{ $form.emails[index].address.error.message }}</Message>
</div>
<Button type="submit" severity="secondary" label="Submit" />
... const data = ref({ username: '', emails: [ { title: '', address: '' }, { title: '', address: '' } ] });

const resolver = ref(
yupResolver(
yup.object().shape({
username: yup.string().required('Username is required via Yup.'),
emails: yup.array(
yup.object({
title: yup.string().required('Email title is required via Yup.'),
address: yup.string().required('Email address is required via Yup.')
})
)
})
)
);
...

Nestet validation not working in this example.
Form states (After submited ):

Data in form: { "valid": false, "username": { "value": "", "touched": false, "dirty": false, "pristine": true, "valid": false, "invalid": true, "error": "ValidationError: Username is required via Yup.", "errors": [ "ValidationError: Username is required via Yup." ] }, "emails[0].title": { "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] }, "emails[0].address": { "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] }, "emails[1].title": { "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] }, "emails[1].address": { "touched": false, "dirty": false, "pristine": true, "valid": true, "invalid": false, "error": null, "errors": [] } }

@drTragger
Copy link

Fixed in 536d21c

You can update the name prop using index.

Exp;

Data in form: {{ $form }}
{{ $form.username.error.message }}
Email Addresses:
Address {{ index + 1 }} {{ $form.emails[index].title.error.message }}
    <InputText v-model="data.emails[index].address" :name="`emails[${index}].address`" type="text" placeholder="Email Address" fluid />
    <Message v-if="$form.emails?.[index]?.address?.invalid" severity="error" size="small" variant="simple">{{ $form.emails[index].address.error.message }}</Message>
</div>
<Button type="submit" severity="secondary" label="Submit" />
... const data = ref({ username: '', emails: [ { title: '', address: '' }, { title: '', address: '' } ] });

const resolver = ref(
yupResolver(
yup.object().shape({
username: yup.string().required('Username is required via Yup.'),
emails: yup.array(
yup.object({
title: yup.string().required('Email title is required via Yup.'),
address: yup.string().required('Email address is required via Yup.')
})
)
})
)
);
...

For me, it does not work. Used the same example you have provided.

@Matheusfrej
Copy link

@arikanaydin and @drTragger , I think the version with the fix is not released yet, so the example provided is not going to work in current version.

@drTragger
Copy link

@Matheusfrej @mertsincan can you please tell me when it is going to be released? I just want to know if I can wait or I should get rid of the PrimeVue form component in my project.

Also, please verify if such cases will work properly:
name=user.username
name=emails[0].primary.address
And so on.

Thanks

@arikanaydin
Copy link

I think the biggest problem here is to address this issue in the next major version transition.

Maybe a structure such as a custom resolver can be built in the next version.
But not being able to use dynamic fields in the current version seems illogical to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement Issue contains an enhancement related to a specific component. Additional functionality has been add
Projects
Status: Done
Development

No branches or pull requests

9 participants