VueJS use v-for variable as attribute value - vue.js

I have an iterative loop that using v-for on an array of objects that then renders a html li item
<li class="block" v-for="(section, key) in sectionDetails">
Item {{ key }}
</li>
The problem here is that key in the tabindex attribute is not being rendered, what IS being rendered is {{ key }}.
How can I get the value of key to be used for tabindex? I've also tried, :tabindex but that gives me a Javascript error.

Interpolation within attributes is not valid in Vue v2.
You need to bind the tabindex attribute to the key like so:
Item {{ key }}
Here's a working fiddle.

Related

How to keep track of parent element in v-for loop?

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.

Elements in iteration expect to have 'v-bind:key' directives in VueApp

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

Custom elements in iteration require 'v-bind:key' directives

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>

How to create an accessor in Vuex?

In Laravel we have Accessors that allow us to get manipulated data from a field or fields.
Is there an equivalent in Vuex? Specifically, I am using a component that takes a collection from Vuex and, for each item, displays {{ item.title }}.
However, {{ item.title }} doesn't exist and should be derived, on a collection by collection basis, when I get the data from Vuex. So it could be from {{ item.name }} or {{ item.postcode }} or whatever.
Is there any way I can do this?

Getting Error "Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key" in index.vue

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.