Displaying a List

You can use the v-repeat directive to repeat a template element based on an Array of objects on the ViewModel. For every object in the Array, the directive will create a child Vue instance using that object as its $data object. These child instances inherit all data on the parent, so in the repeated element you have access to properties on both the repeated instance and the parent instance. In addition, you get access to the $index property, which will be the corresponding Array index of the rendered instance.

Example:

1
2
3
4
5
<ul id="demo">
<li v-repeat="items" class="item-{{$index}}">
{{$index}} - {{parentMsg}} {{childMsg}}
</li>
</ul>
1
2
3
4
5
6
7
8
9
10
var demo = new Vue({
el: '#demo',
data: {
parentMsg: 'Hello',
items: [
{ childMsg: 'Foo' },
{ childMsg: 'Bar' }
]
}
})

Result:

Fragment Repeat

Sometimes you might want to repeat a fragment of more than one nodes - in that case, you can use a <template> tag to wrap the repeat fragment. The <template> tag here merely serves as a semantic wrapper. For example:

1
2
3
4
5
6
<ul>
<template v-repeat="list">
<li>{{msg}}</li>
<li class="divider"></li>
</template>
</ul>

Arrays of Primitive Values

For Arrays containing primitive values, you can access the value simply as $value:

1
2
3
4
5
<ul id="tags">
<li v-repeat="tags">
{{$value}}
</li>
</ul>
1
2
3
4
5
6
new Vue({
el: '#tags',
data: {
tags: ['JavaScript', 'MVVM', 'Vue.js']
}
})

Result:

Using an alias

Sometimes we might want to have more explicit variable access instead of implicitly falling back to parent scope. You can do that by providing an alias to the v-repeat directive and use it as the alias for the item being iterated:

1
2
3
4
5
<ul id="users">
<li v-repeat="user in users">
{{user.name}} - {{user.email}}
</li>
</ul>
1
2
3
4
5
6
7
8
9
new Vue({
el: '#users',
data: {
users: [
{ name: 'Foo Bar', email: 'foo@bar.com' },
{ name: 'John Doh', email: 'john@doh.com' }
]
}
})

Result:

The user in users syntax is only available in Vue 0.12.8 and above. For older versions, you must use the user : users syntax.

Using an alias with v-repeat in general results in more readable templates and slightly better performance.

Mutation Methods

Under the hood, Vue.js intercepts an observed Array’s mutating methods (push(), pop(), shift(), unshift(), splice(), sort() and reverse()) so they will also trigger View updates.

1
2
3
// the DOM will be updated accordingly
demo.items.unshift({ childMsg: 'Baz' })
demo.items.pop()

Augmented Methods

Vue.js augments observed Arrays with two convenience methods: $set() and $remove().

You should avoid directly setting elements of a data-bound Array with indices, because those changes will not be picked up by Vue.js. Instead, use the augmented $set() method:

1
2
// same as `demo.items[0] = ...` but triggers view update
demo.items.$set(0, { childMsg: 'Changed!'})

$remove() is just syntax sugar for splice(). It will remove the element at the given index. When the argument is not a number, $remove() will search for that value in the array and remove the first occurrence.

1
2
// remove the item at index 0
demo.items.$remove(0)

Replacing an Array

When you are using non-mutating methods, e.g. filter(), concat() or slice(), the returned Array will be a different instance. In that case, you can just replace the old Array with the new one:

1
2
3
demo.items = demo.items.filter(function (item) {
return item.childMsg.match(/Hello/)
})

You might think this will blow away the existing DOM and re-build everything. But worry not - Vue.js recognizes array elements that already have an associated Vue instance and will reuse those instances whenever possible.

Using track-by

In some cases, you might need to replace the Array with completely new objects - e.g. ones returned from an API call. Since by default v-repeat determines the reusability of an existing child instance and its DOM nodes by tracking the identity of its data object, this could cause the entire list to be re-rendered. However, if each of your data objects has a unique id property, then you can use a track-by param to give Vue.js a hint so that it can reuse existing instances as much as possible.

For example, if your data looks like this:

1
2
3
4
5
6
{
items: [
{ _uid: '88f869d', ... },
{ _uid: '7496c10', ... }
]
}

Then you can give the hint like this:

1
2
3
<div v-repeat="items" track-by="_uid">
<!-- content -->
</div>

Later on, when you replace the items array and Vue.js encounters a new object with _uid: '88f869d', it knows it can reuse the existing instance with the same _uid.

If you don’t have a unique key to track by, you can also use track-by="$index". Make sure to use this carefully though, because when tracking by $index, instead of moving the child instances and DOM nodes, Vue will simply reuse them in place in the order they were first created. Avoid using track-by="$index" in two situations: when your repeated block contains form inputs that can cause the list to re-render; or when you are repeating a component with mutable state in addition to the repeated data being assigned to it.

Using track-by properly can greatly increase the performance when re-rendering large v-repeat lists using completely new data.

Iterating Through An Object

You can also use v-repeat to iterate through the properties of an Object. Each repeated instance will have a special property $key. For primitive values, you also get $value which is similar to primitive values in Arrays.

1
2
3
4
5
<ul id="repeat-object">
<li v-repeat="primitiveValues">{{$key}} : {{$value}}</li>
<li>===</li>
<li v-repeat="objectValues">{{$key}} : {{msg}}</li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
new Vue({
el: '#repeat-object',
data: {
primitiveValues: {
FirstName: 'John',
LastName: 'Doe',
Age: 30
},
objectValues: {
one: {
msg: 'Hello'
},
two: {
msg: 'Bye'
}
}
}
})

Result:

In ECMAScript 5 there is no way to detect when a new property is added to an Object, or when a property is deleted from an Object. To deal with that, observed objects will be augmented with three methods: $add(key, value), $set(key, value) and $delete(key). These methods can be used to add / delete properties from observed objects while triggering the desired View updates. The difference between $add and $set is that $add will return early if the key already exists on the object, so just calling obj.$add(key) won’t overwrite the existing value with undefined.

Iterating Over a Range

v-repeat can also take an integer Number. In this case it will repeat the template that many times.

1
2
3
<div id="range">
<div v-repeat="val">Hi! {{$index}}</div>
</div>
1
2
3
4
5
6
new Vue({
el: '#range',
data: {
val: 3
}
})

Result:

Array Filters

Sometimes we only need to display a filtered or sorted version of the Array without actually mutating or resetting the original data. Vue provides two built-in filters to simplify such usage: filterBy and orderBy. Check out their documentations for more details.

Next up: Listening for Events.