v-for
We can use the v-for
directive to render a list of items based on an array. The v-for directive requires a special syntax in the form of item in items
, where items
is the source data array and item
is an alias for the array element being iterated on:
1
2
3
4
5
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
1
2
3
<li v-for="item in items">
{{ item.message }}
</li>
Inside the v-for
scope, template expressions have access to all parent scope properties. In addition, v-for
also supports an optional second alias for the index of the current item:
1
2
3
4
5
6
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
1
2
3
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
The variable scoping of v-for is similar to the following JavaScript:
1
2
3
4
5
6
7
8
9
10
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// has access to outer scope `parentMessage`
// but `item` and `index` are only available in here
console.log(parentMessage, item.message, index)
})
Notice how the v-for
value matches the function signature of the forEach
callback. In fact, you can use destructuring on the v-for
item alias similar to destructuring function arguments:
1
2
3
4
5
6
7
8
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- with index alias -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
For nested v-for
, scoping also works similar to nested functions. Each v-for
scope has access to parent scopes:
1
2
3
4
5
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
You can also use of
as the delimiter instead of in
, so that it is closer to JavaScript’s syntax for iterators:
1
<div v-for="item of items"></div>
v-for
with an Object
You can also use v-for
to iterate through the properties of an object. The iteration order will be based on the result of calling Object.keys()
on the object:
1
2
3
4
5
6
7
8
9
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
1
2
3
4
5
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
You can also provide a second alias for the property’s name (a.k.a. key):
1
2
3
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
And another for the index:
1
2
3
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
v-for
with a Range
v-for
can also take an integer. In this case it will repeat the template that many times, based on a range of 1...n
.
1
<span v-for="n in 10">{{ n }}</span>
Note here n
starts with an initial value of 1
instead of 0
.
v-for
on <template>
Similar to template v-if
, you can also use a <template>
tag with v-for
to render a block of multiple elements. For example:
1
2
3
4
5
6
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for
with v-if
Note
It’s not recommended to use
v-if
andv-for
on the same element due to implicit precedence. Refer to style guide for details.
When they exist on the same node, v-if
has a higher priority than v-for
. That means the v-if
condition will not have access to variables from the scope of the v-for
:
1
2
3
4
5
6
7
<!--
This will throw an error because property "todo"
is not defined on instance.
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
This can be fixed by moving v-for
to a wrapping <template>
tag (which is also more explicit):
1
2
3
4
5
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>