javascriptvue.jscontextmenuv-forprimevue

Primevue ContextMenu inside v-for loop not working


I have the following vue code using PrimeVue. I'm currently following this tutorial ContextMenu

<!-- Vue Component -->
<script>
    const dt = ref()
    const cm = ref()
    const data = ref([
        {id: 1, col1: 100, col2: 'foo', ...},
        {id: 2, col1: 200, col2: 'bar', ...},
        ...
    ])
    const selectedData = ref()
    const menuModel = ref([
        { label: 'Edit', icon: 'pi pi-fw pi-pencil', command: () => console.log('edit') },
        { label: 'Delete', icon: 'pi pi-fw pi-times', command: () => console.log('delete') }
    ])

    function onRowContextMenu (event) {
        cm.value.show(event.originalEvent)
    }
</script>

<template>
    <!-- OTHER STUFF HERE -->
    <ContextMenu ref="cm" :model="menuModel" @hide="selectedData= null" />
    <DataTable :value="data" ref="dt" dataKey="id" contextMenu v-model:contextMenuSelection="selectedData" @rowContextmenu="onRowContextMenu" >
        <Column>...</Column>
        ...
    </DataTable>
    <!-- OTHER STUFF HERE -->
</template>

The code above is working fine, but when i tried to wrap <ContextMenu> and <DataTable> inside <template> like this (below).

<!-- Vue Component -->
<script>
    // SAME AS ABOVE
    const menus = ref([
        { header: 'h1', label: 'lab1', ... },
        { header: 'h2', label: 'lab2', ... },
        ...
    ])
</script>

<template>
    <!-- OTHER STUFF HERE -->
    <template v-for="(menu, index) in menus" :key="index">
        <ContextMenu ref="cm" :model="menuModel" @hide="selectedData= null" />
        <DataTable :value="data" ref="dt" dataKey="id" contextMenu v-model:contextMenuSelection="selectedData" @rowContextmenu="onRowContextMenu" >
            <Column>...</Column>
            ...
        </DataTable>
    </template>
    <!-- OTHER STUFF HERE -->
</template>

Suddenly, it returns an error, Uncaught TypeError: cm.value.show is not a function. Any idea why this happened, and how to fix it?

Btw, for context, menus inside v-for is just a simple array to create multiple <DataTable> with <ContextMenu>.


Solution

  • Because your template ref cm is now in a v-for, it has been turned into an array of template refs. You can read about this behavior in the Vue documentation.

    show() doesn't exist as an array function, you need to specify an index first. You can pass the index in your event listener:

    @rowContextmenu="onRowContextMenu($event, index)"
    
    function onRowContextMenu (event, index) {
      cm.value[index].show(event.originalEvent)
    }