Raj
Raj

Reputation: 1655

Error asking for :key to be placed on <template>

For not having :key="item.id" on <template>, I'm getting this error:

error1

But when I do put it on there as such:

<template v-for="item in Object.values(cart)" :key="item.id">

…then I get this error:

enter image description here

Here's the code in question:

          <template v-for="item in Object.values(cart)">
            <tr :key="item.id">
              <td>Digest {{ item.digestId }}</td>
              <td>{{ item.duration_text }} subscription</td>
              <td class="price-cell">${{ roundMoney(item.price, 2) }}</td>
              <td class="trash-cell">
                <fa-icon icon="times-circle" size="lg" @click="removeItem(item)" />
              </td>
            </tr>
            <tr v-if="item.discounts.length" :key="`${item.id}-${item.discounts && item.discounts[0].id}`">
              <td colspan="2">
                <label>Code: {{ item.discounts[0].code }}</label>
              </td>
              <td colspan="2">
                <span class="discount-amount">–${{ item.discounts[0].percent_off }}</span>
              </td>
              <td class="trash-discount-cell">
                <fa-icon icon="times-circle" class="trash" @click="rmDscnt(item.discounts[0])" />
              </td>
            </tr>
          </template>

How might I get around this circular-seeming issue?

Upvotes: 6

Views: 7392

Answers (4)

Matt Schlosser
Matt Schlosser

Reputation: 1044

I recently got this error and was able to fix it by setting up Volar to use Vue 2.7 instead

// tsconfig.json
{
  "compilerOptions": {
    // ...
  },
  "vueCompilerOptions": {
    "target": 2.7,
    // "target": 2, // For Vue version <= 2.6.14
  }
}

Upvotes: 1

Ximu_Luya
Ximu_Luya

Reputation: 161

Although it has been a year since this question, I recently encountered a similar problem in discussions with others and found the reason for the problem. I hope my answer can help other friends who see this answer.

The tag of the questioner is vue3. In vue3, the v-for standard syntax is used on the template tag to write the key on the template tag. Please see the official document here: https://v3.vuejs.org/guide/list.html#v-for-on-a-template.

as follows:

<template v-for="item in Object.values(cart)" :key="item.id">

I think the reason for the infinite loop error of the questioner is that the rules of vue2 and vue3 are used at the same time. My vue2 project uses the volar plugin also to cause this error. Use v-for on template tag, vue2 and vue3 use two kinds of rules.

vue2: vue/no-v-for-template-key vue3: vue/no-v-for-template-key-on-child

These two rules conflict with each other. Here is the official guidance document: https://eslint.vuejs.org/rules/no-v-for-template-key-on-child.html

I did not give a solution, because I am not clear about the other configuration of the questioner, but I think I have found the reason, and hope to help you troubleshoot the problem

Upvotes: 12

Robson Martins
Robson Martins

Reputation: 46

As explained by others, Vue.js will use the tag for rendering and compilation, it will not really exist in the DOM. The keys are required so that Vue's diffing algorhythm can tell the different instances of the components apart.

That said, after check your example I realized you do not need here, I assume your is inside a or tag, so you can simply v-for the itself.

Example:

    <table>
    <tbody>
        <tr v-for="item in Object.values(cart)" :key="item.id">
            <td>Digest {{ item.digestId }}</td>
            <td>{{ item.duration_text }} subscription</td>
            <td class="price-cell">${{ roundMoney(item.price, 2) }}</td>
            <td class="trash-cell">
                <fa-icon icon="times-circle" size="lg" @click="removeItem(item)" />
            </td>
        </tr>
        <tr v-if="item.discounts.length" :key="`${item.id}-${item.discounts && item.discounts[0].id}`">
            <td colspan="2">
                <label>Code: {{ item.discounts[0].code }}</label>
            </td>
            <td colspan="2">
                <span class="discount-amount">–${{ item.discounts[0].percent_off }}</span>
            </td>
            <td class="trash-discount-cell">
                <fa-icon icon="times-circle" class="trash" @click="rmDscnt(item.discounts[0])" />
            </td>
        </tr>
    </tbody>
</table>

I will take the chance to give you another tip I use on my own codes, instead of using record attributes, for example, 'item.id' I use the index generated by the looping that will always have a sequence avoiding duplicated errors and the most important, it will always have a valid value.

Example:

<tr v-for="(item, index) in Object.values(cart)" :key="`items_${index}`">

If it helps you, please, mark as answered.

Happy coding!

Upvotes: -1

jlopezlira
jlopezlira

Reputation: 1

Vue use template tag to know if is a component also like react you must return one element try this:

      <template>
        <div>
         <section v-for="item in Object.values(cart)">
        <tr :key="item.id">
          <td>Digest {{ item.digestId }}</td>
          <td>{{ item.duration_text }} subscription</td>
          <td class="price-cell">${{ roundMoney(item.price, 2) }}</td>
          <td class="trash-cell">
            <fa-icon icon="times-circle" size="lg" @click="removeItem(item)" />
          </td>
        </tr>
        <tr v-if="item.discounts.length" :key="`${item.id}-${item.discounts && item.discounts[0].id}`">
          <td colspan="2">
            <label>Code: {{ item.discounts[0].code }}</label>
          </td>
          <td colspan="2">
            <span class="discount-amount">–${{ item.discounts[0].percent_off }}</span>
          </td>
          <td class="trash-discount-cell">
            <fa-icon icon="times-circle" class="trash" @click="rmDscnt(item.discounts[0])" />
          </td>
        </tr>
        </section>
        </div>
      </template>

Upvotes: -1

Related Questions