VueJS #3 Rendering Lists 1.0

Catalogue
  1. 1. v-for
  2. 2. v-for with an Object
  3. 3. v-for with a Range
  4. 4. v-for on <template>
  5. 5. v-for with v-if

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>

v-for

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 an Object

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 and v-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>