This error comes up:
[vue/require-v-for-key]
Elements in iteration expect to have 'v-bind:key' directives.
Codepen - https://codesandbox.io/s/competent-pine-8u9mt?file=/src/components/Laptops.vue:386-393
Does anybody know how to solve this error?
When using v-for, vue expects a unique key for each iteration. You can achieve this by binding an index key to your div element
<div v-for="(product, index) in products" :key="index">
// code to execute
</div>
:key is shorthand for v-bind:key
Related
I'm trying to change text inside div elements that contain html tags into actual html. I have a v-for loop which lists all the text items into divs.
<li v-for="item in items">
<div id="description" class="content">{{item.description}}</div>
</li>
The whole text just includes the html element rather than turning it into html which is not what I want.
I thought about pumping it through a function that would call document.innerHTML() on it but Im not sure how to make the parent have a unique ID to call it on. I'd like to keep track of the parent the item is from with either an unique ID or as some sort of parameter.
Answering this for anyone who doesn't read the comments like me :-)
v-html will render an HTML snippet to the page.
The second part of your question involves telling Vue that each element is unique. You do this with a :key. These give Vue's Virtual DOM a unique ID for your element. You can use a unique element in your data for the key or an iteration number.
If you will need to access the ID for something else OUTSIDE of Vue's reactivity, use a Vue ref.
So combining all of that your code becomes:
<li v-for="item in items" :key="item.name" ref="myItems">
<div id="description" class="content" v-html="item.description"></div>
</li>
or with a number for the key
<li v-for="(item, n) in items" :key="n" ref="myItems">
<div id="description" class="content" v-html="item.description"></div>
</li>
Note: when ref's are used in a v-for they produce an array. So in this case myItems.length == items.length and myItems[n] is a unique reference.
I am new to VueJS and I have a simple HTML markup where I iterate through some objects and render them in html like so:
<div v-for="item in some_counter">
<p v-if="item.some_param1 !== 'None'">
[[ item.some_param2 ]]
</p>
</div>
However, I notice that even when the condition evaluates to false, I see an extra HTML <div></div> markup. This seems very odd to me, coming from the Django world.
How do I avoid this extra markup?
The v-if applies to the element you place it on. So if you want to conditionally include the <div> you need to put the v-if on the <div> (or a parent element). It won't remove the <div> just because it is empty.
Technically you can have both v-for and v-if on the same element but it is generally discouraged as it can be confusing trying to understand which is applied first (see https://v2.vuejs.org/v2/guide/list.html#v-for-with-v-if). Instead you should include a wrapping <template> for the v-for:
<template v-for="item in some_counter">
<div v-if="item.some_param1 !== 'None'">
<p>
[[ item.some_param2 ]]
</p>
</div>
</template>
The <template> tag is special and won't add an extra element to the finished DOM.
An alternative approach would be to filter the list of items in a computed property and then iterate over the filtered list in your template.
In my Nuxt app I have the following line that triggers the error mentioned in the title of this question:
<template v-for="(project, index) in existingProjects">
<span :key="project.projectId"></span>
I tried to have the :key attribute on the template element and I also tried to use just index as the key, to no avail.
Any idea?
There are multiple ways to solve your problem :
You want to iterate on a template :
You have to put a key on all elements in your template because you can not put a key on a template: <template> cannot be keyed. Place the key on real elements instead.
<template v-for="(project, index) in existingProjects">
<span :key="project.projectId">foo</span>
<div :key="project.projectId">bar</div>
</template>
You can iterate on something else than a template : You just put the key on the parent html tag.
<div v-for="(project, index) in existingProjects" :key="project.projectId">
<span>foo</span>
<div>bar</div>
</div>
I am new to vue.js. I have a simple index.vue which tries to connect to contentful and display the entries from contentful. My code in index.vue looks like this:
<template>
<div>
<!-- render data of the person -->
<h1>{{ person.fields.name }}</h1>
<!-- render blog posts -->
<ul>
<li v-for="post in posts">
{{ post.fields.title }}
</li>
</ul>
</div>
</template>
<script>
import {createClient} from '~/plugins/contentful.js'
const client = createClient()
However when I try localhost:3000 from my browser...it comes back with the following error:
ERROR in ./pages/index.vue
Module Error (from ./node_modules/eslint-loader/index.js):
C:\Users\admin\pdress\pages\index.vue
7:7 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
✖ 1 problem (1 error, 0 warnings)
I appreciate if someone can help me out to proceed further with my learning on vue.js please. Thanks in advance
What #ljubadr suggested is right. You need to do this:
<li v-for="post in posts" v-bind:key="post.id">
<!-- OR USE SHORTCUT NOTATION -->
<li v-for="post in posts" :key="post.id">
The reason has to do with performance. Attribute key helps Vue determine unique items in a list. Consider the example of sorting. If your UI has a sort button for posts, then your the order of items in post array will change. But does that mean Vue is going to re-render entire list? Of course not! Using :key it can determine if the item was already rendered on UI. It simply shuffles the DOM nodes and saves expensive rendering cycles.
Secondly, if you have complex components within your list when you are using v-for and :key is not provided, then whenever the list is changed or re-ordered, it simply changes the DOM but doesn't destroy existing components and that can cause local state mismatch. That is why it is must to have :key attribute.
Read Vue.js documentation for further information.
Note: Also remember that using v-for index for :key is a bad idea as it is not unique across your collection.
<template>
<div>
<!-- render data of the person -->
<h1>{{ person.fields.name }}</h1>
<!-- render blog posts -->
<ul>
<li v-for="post in posts" :key = "post">
{{ post.fields.title }}
</li>
</ul>
</div>
</template>
If this is not going to work use any unique field from your object for example if you have id in your object then,
:key = "post.id"
You must define a :key atribute for
v-for directive. And for <transition-group> tag.
for this case v-for you must explicit set,
<li v-for="(post, i) in posts" :key="i + 10">
{{ post.fields.title }}
</li>
If you noticed you can define max two argument in the v-for you must define the item (post) and can define the index of the post.
To put as simply as possible:
I have a v-for loop. I'd like to access an specific element inside one of the iterations of the loop. For reasons, I can only do this using ref. Is there a way of doing this?
I have tried various different ways of achieving this, but it always returns undefined. My code works fine outside of a v-for loop.
The documentation for vue doesn't cover this instance.
The loop simplified:
<div v-for="(item, i) in items">
<div ref="card"></div>
</div>
The Method
doThing() {
card = elements.create('card');
card.mount(this.$refs.card);
}
Since array refs are not guaranteed to be in the original order, I've found it more helpful to register a ref on the parent, then use the regular DOM API to find the element you want.
Template
<div ref="cards">
<div v-for="(item, i) in items">
<!-- this is a card -->
</div>
</div>
JavaScript
{
methods: {
getCardAt(index) {
return this.$refs.cards.children[index];
}
}
}
You could try this:
<div v-for="(item, i) in items">
<div :ref="`card-${i}`"></div>
</div>
Refs in a v-for loop become arrays with each element at the index it appears in the document. It is covered here ~ https://v2.vuejs.org/v2/api/#ref
When used on elements/components with v-for, the registered reference will be an Array containing DOM nodes or component instances.
So to "access an specific element inside one of the iterations of the loop", you would use something like
card.mount(this.$refs.card[someIndex])