accordion-item not picking up v-for directive variable
This sample component below displays "foo" in both accordion items.
Can the code be fixed to properly display "foo" & "bar", without moving the accordion construction to javascript?
Related question: how can I specify the data to pass to the item's content template (#content="{}") - again without resorting to the JS APIs?
Thanks!
<template>
<ejs-accordion>
<e-accordionitems>
<template v-for="(name) in names">
<e-accordionitem content="content" header="header">
<template #content="{}">
Names: {{ name }}
</template>
</e-accordionitem>
</template>
</e-accordionitems>
</ejs-accordion>
</template>
<script lang="ts" setup>
import {
AccordionComponent as EjsAccordion, AccordionItemsDirective as EAccordionitems, AccordionItemDirective as EAccordionitem
} from "@syncfusion/ej2-vue-navigations";
const names = [ "foo", "bar"]
</script>
Hi Franck Mangin,
Thank you for reaching out. We've reviewed your code and found a way to achieve your desired outcome. The issue was related to how the content for each accordion item was being set.
In Vue, you can bind data to component properties using the v-bind directive (or its shorthand :). In your case, you can bind the name variable to the content and header properties of the e-accordionitem. Here's the corrected code:
|
<template> <ejs-accordion> <e-accordionitems> <e-accordionitem v-for="(name, index) in names" :key="index" :header="'Names: ' + name" :content="name"> </e-accordionitem> </e-accordionitems> </ejs-accordion> </template>
<style> @import ../node_modules/@syncfusion/ej2-navigations/styles/material.css; @import ../node_modules/@syncfusion/ej2-buttons/styles/material.css; @import ../node_modules/@syncfusion/ej2-base/styles/material.css; </style>
<script setup> import { AccordionComponent as EjsAccordion, AccordionItemsDirective as EAccordionitems, AccordionItemDirective as EAccordionitem, Accordion, } from "@syncfusion/ej2-vue-navigations";
const names = [ "foo", "bar"] </script> |
In this code, the :content attribute is bound to the name variable, which sets the content of each accordion item to the corresponding name. The :header attribute is also bound to a dynamic string that includes the name variable, which sets the header of each accordion item to "Names: " followed by the name.
We hope this helps! If you have any other questions, please don't hesitate to ask.
Regards,
Ram
Hi Ram,
Thanks for yoru suggestion but that doesn't help. I need to use a complex embedded template as the accordion item, and I don't want to define it in javascript.
In the solution you proposed for example the items will display "foo" and "bar" instead of "Names: foo" and "Names: bar"... and this was a simplified example, my actual code uses an external component:
<template v-for="(slot) in slots">
<e-accordionitem content="content" header="header">
<template #content="{}">
<SlotSchedule v-if="slot.useSessions" :slotId="slot.id"/>
<SlotCalendar v-else :slotId="slot.id"/>
</template>
</e-accordionitem>
...
In other terms I want to use a named slot to define the item content, how can I pass data to that slot?
The approach is described here on your blog: https://www.syncfusion.com/blogs/post/introducing-slot-template-support-for-syncfusion-vue-components.aspx/amp
Franck
Hi Franck Mangin,
In response to your query, you can use Vue's dynamic slot names and conditional rendering to customize the content of each accordion item. Here's a code snippet demonstrating this:
|
<template> <ejs-accordion> <e-accordionitems> <e-accordionitem v-for="(slot, index) in slots" :key="index" :header="'Slot: ' + slot.id" :content="getContent(slot, index)"> <template v-if="getContent(slot, index)===`scheduleTemplate`" v-slot:scheduleTemplate> <SlotSchedule :slotId="slot.id"/> </template> <template v-if="getContent(slot, index)===`calendarTemplate`" v-slot:calendarTemplate> <SlotCalendar :slotId="slot.id"/> </template> </e-accordionitem> </e-accordionitems> </ejs-accordion> </template> |
The getContent function determines the slot name based on the useSessions property of each slot. We then conditionally render the templates for 'scheduleTemplate' and 'calendarTemplate' based on this slot name.
This approach allows you to use a complex embedded template for the accordion item and pass data to it.
Please check the attached sample for a complete implementation of this solution.
Regards,
Ram
Attachment: VueCompositionEditorTemplate_(2)_241a7272.zip
Thanks, unfortunately this doesn't work, you are back to my initial issue: slot.id is always "1" inside the named slot.
The :content binding does see the right slot, but the named v-slots do not.
<SlotSchedule :slotId="slot.id"/>
I need access to the (slot, index) data bound by the v-for
Here is a complete example that show the issue:
<template>
<ejs-accordion>
<e-accordionitems>
<e-accordionitem v-for="(slot, index) in slots" :key="index" :content="getContent(slot)"
:header="'Slot: ' + slot.id">
<template v-slot:scheduleTemplate="{}">
Slot ID: {{ slot.id }}
</template>
<template v-slot:calendarTemplate="{}">
Slot ID: {{ slot.id }}
</template>
</e-accordionitem>
</e-accordionitems>
</ejs-accordion>
</template>
<script lang="ts" setup>
import {
AccordionComponent as EjsAccordion,
AccordionItemDirective as EAccordionitem,
AccordionItemsDirective as EAccordionitems
} from "@syncfusion/ej2-vue-navigations";
const slots = [{id: 1, useSessions: true}, {id: 2, useSessions: false}];
const getContent = (slot: any) => slot?.useSessions ? 'scheduleTemplate' : 'calendarTemplate';
</script>
Hi Franck Mangin,
Based on your query, it appears that you're having trouble accessing the correct slot.id within your named slots in Vue. This issue arises due to the same template being used for both accordion items.
To resolve this, you can add a v-if check before
rendering the template. This will ensure that the correct template is used for
each accordion item based on the getContent(slot) function. Here's how you can
modify your code:
|
<template> <ejs-accordion> <e-accordionitems> <e-accordionitem v-for="(slot, index) in slots" :key="index" :content="getContent(slot)" :header="'Slot: ' + slot.id"> <template v-if="getContent(slot, index)===`scheduleTemplate`" v-slot:scheduleTemplate="{}"> Slot ID: {{ slot.id }} </template> <template v-if="getContent(slot, index)===`calendarTemplate`" v-slot:calendarTemplate="{}"> Slot ID: {{ slot.id }} </template> </e-accordionitem> </e-accordionitems> </ejs-accordion> </template> |
In the above code, the v-if directive checks whether the getContent(slot) function returns 'scheduleTemplate' or 'calendarTemplate'. Depending on the result, the corresponding template is rendered, ensuring that the correct slot.id is accessed.
Regards,
Ram
Please do check the value of slot.id in this named slot:
<template v-if="getContent(slot, index)===`scheduleTemplate`" v-slot:scheduleTemplate="{}">
Slot ID: {{ slot.id }}
</template>
... you will find that it is not correct.
I think this is a feature request in the end, what would make this work is something like this: a new itemDataSource property on the accordionitem, that the directive would provide to named slots.
Today it provies the root accordion datasource as data, which is useless since the item doesn't know what element to pick in the array.
<template>
<ejs-accordion>
<e-accordionitems>
<e-accordionitem v-for="(slot, index) in slots" :key="index" :content="content" :item-data-source="slot">
<template #content="mySlot">
Slot ID: {{ mySlot.id }}
</template>
</e-accordionitem>
</e-accordionitems>
</ejs-accordion>
</template>
<script lang="ts" setup>
import {
AccordionComponent as EjsAccordion,
AccordionItemDirective as EAccordionitem,
AccordionItemsDirective as EAccordionitems
} from "@syncfusion/ej2-vue-navigations";
const slots = [{id: 1, useSessions: true}, {id: 2, useSessions: false}];
const getContent = (slot: any) => slot?.useSessions ? 'scheduleTemplate' : 'calendarTemplate';
</script>
Hi Franck Mangin,
We observed that in the provided sample, the template was not dynamically rendered, and the initial value was set to the templates. To address this issue, we have provided a corrected code snippet that utilizes the v-for directive to dynamically render the templates based on the values in the slots array. The :content property is appropriately set to generate unique content slots for each accordion item, ensuring that the named slot in the template correctly references the slot.id value.
Please find the corrected code below:
|
<template> <ejs-accordion> <e-accordionitems> <e-accordionitem v-for="(slot, index) in slots" :key="index" :content="`content${slot.id}`" :header="'Slot: ' + slot.id" :item-data-source="slot"> <template #[`content${slot.id}`]> Slot ID: {{ slot.id }} </template> </e-accordionitem> </e-accordionitems> </ejs-accordion> </template> <script lang="ts" setup> import { AccordionComponent as EjsAccordion, AccordionItemDirective as EAccordionitem, AccordionItemsDirective as EAccordionitems } from "@syncfusion/ej2-vue-navigations"; const slots = [{id: 1, useSessions: true}, {id: 2, useSessions: false}]; const getContent = (slot: any) => slot?.useSessions ? 'scheduleTemplate' : 'calendarTemplate'; </script> |
We have attached the runnable sample for your reference.
Regards,
Ram
- 7 Replies
- 2 Participants
-
FM Franck Mangin
- Jan 29, 2024 02:57 PM UTC
- Feb 8, 2024 11:47 AM UTC