Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue: template can't be keyed, but can't replace template with div - need the v-for without a wrapper div element, nested v-for loops

I have this JSON:

{
   "data":{
      "1":{
         "color":"red",
         "size":"big"
      },
      "2":{
         "color":"red",
         "size":"big"
      },
      "3":{
         "color":"red",
         "size":"big"
      },
      "4":{
         "color":"red",
         "size":"big"
      },
      "5":{
         "color":"red",
         "size":"big"
      }
   }
}

that I display with this vue code:

<template>
...

<template v-for="(obj, pos) in this.breakdown" :key="pos">
    <table class="table-auto" >
        <thead>
            <tr>
                <th class="px-4 py-2">Property</th>
                <th class="px-4 py-2">Value</th>
            </tr>
        </thead>

        <tbody>
            <template v-for = "(obj2, pos2) in obj" :key="pos2">
                <tr>
                    <td class="border px-4 py-2">
                        {{pos2}}
                    </td>
                    <td class="border px-4 py-2">
                        {{obj2}}
                    </td>
                </tr>
            </template>
        </tbody>
    </table>
</template>
...
</template>

However I get the error '<template>' cannot be keyed. Place the key on real elements error. If I replace template with span or div, it works, but the styling is all out of place, so I need it to be without the wrapper element - I've read it's only achievable with the template tag, but then I'm not sure how to modify the v-for loops to remove the error.

like image 421
parsecer Avatar asked Jun 04 '20 19:06

parsecer


People also ask

What is V-for in Vue?

v-for directive is a Vue. js directive used to loop over a data usually an array or object. First, we will create a div element with id as app and let's apply the v-for directive to an element with data.

What is key in V-for?

The purpose of this key attribute is to give "a hint for Vue's virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list" (from Vue. js Docs). Essentially, it helps Vue identify what's changed and what hasn't.

How do I add templates to Vue?

Just put your <script> tag based template inside of something. html on your server. If you are using jQuery, . load should work.

What does template tag do in Vue?

Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component instance's data.


2 Answers

Try to put v-for into template and key on tr.

<template v-for="(i, j) in list" >   
            <tr :key="'1tr-'+j"> 
               <td..../>
            </tr>
            <tr :key="'2tr-'+j"> 
               <td..../>
            </tr>
 </template>

This is working for me. Hope it will

like image 66
Jainith Patel Avatar answered Oct 08 '22 17:10

Jainith Patel


In my case I need to render a sidebar menu. The menu items could be single elements or submenus. I tried this:

export interface DashboardRoute {
  icon: string
  label: string
  children?: string[]
}

const dashboardRoutes: DashboardRoute[] = [
  {
    label: 'Visão geral',
    icon: 'dashboard',
  },
  {
    label: 'Pessoas',
    icon: 'user',
  },
  {
    label: 'Categorias',
    icon: 'tags',
    children: [
      'Todas as categorias',
      'Alimentação',
      'Refeição',
    ],
  },
]

export default dashboardRoutes
<a-menu v-for="{ icon, label, children } in dashboardRoutes" :key="label" mode="inline">
  <a-sub-menu v-if="children">
    <span slot="title"
      ><a-icon :type="icon" /><span>{{ label }}</span></span
    >
    <a-menu-item v-for="child in children" :key="child">
      {{ child }}
    </a-menu-item>
  </a-sub-menu>
  <a-menu-item v-else>
    <a-icon :type="icon" />
    <span class="nav-text">{{ label }}</span>
  </a-menu-item>
</a-menu>

But this is not right. It will create multiple a-menu elements and should have a single one.

So I naively tried this:

<a-menu mode="inline">
  <template v-for="{ icon, label, children } in dashboardRoutes" :key="label">
    <a-sub-menu v-if="children">
      <span slot="title"
        ><a-icon :type="icon" /><span>{{ label }}</span></span
      >
      <a-menu-item v-for="child in children" :key="child">
        {{ child }}
      </a-menu-item>
    </a-sub-menu>
    <a-menu-item v-else>
      <a-icon :type="icon" />
      <span class="nav-text">{{ label }}</span>
    </a-menu-item>
  </template>
</a-menu>

which shows this error you found. So I googled it and found this issue. The solution is to move the key prop from template to the first child element, or to the siblings (if they exists - thats my case).

So, the solution will be

<a-menu mode="inline">
  <template v-for="{ icon, label, children } in dashboardRoutes">
    <a-sub-menu v-if="children" :key="label"> <!-- key comes here! -->
      <span slot="title"
        ><a-icon :type="icon" /><span>{{ label }}</span></span
      >
      <a-menu-item v-for="child in children" :key="child"> 
        {{ child }}
      </a-menu-item>
    </a-sub-menu>
    <a-menu-item v-else :key="label"> <!-- key comes here! -->
      <a-icon :type="icon" />
      <span class="nav-text">{{ label }}</span>
    </a-menu-item>
  </template>
</a-menu>
like image 36
Michael Pacheco Avatar answered Oct 08 '22 18:10

Michael Pacheco