Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Lists: v-for and key

The v-for directive repeats an element for every value of an array. Instead of a loop that creates elements with createElement, you describe one element, and Vue renders as many as there are records in the data.

Rendering an array

<!-- src/App.vue -->
<script setup>
import { ref } from 'vue'
 
const todos = ref([
  { id: 1, text: 'Buy bread', done: true },
  { id: 2, text: 'Call Anna', done: false },
  { id: 3, text: 'Write a report', done: false },
])
</script>
 
<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
    </li>
  </ul>
</template>

The page shows a list of three tasks. todo in todos works like for...of: the todo variable takes each task in turn and is available inside li.

The key attribute

:key is a unique key of the element. Vue uses it to know which DOM element belongs to which record when the list changes: when a task is removed from the middle, it removes exactly that li instead of re-rendering every row. Use the id from the data as the key — a string or number that never repeats.

Index

A second variable in parentheses gives the element's position:

<template>
  <ul>
    <li v-for="(todo, index) in todos" :key="todo.id">
      {{ index + 1 }}. {{ todo.text }}
    </li>
  </ul>
</template>

The rows get numbers: "1. Buy bread", "2. Call Anna" and so on. Indexes start at zero, so one is added.

Changing the list

The list on the page updates when the array changes:

<script setup>
import { ref } from 'vue'
 
const todos = ref([
  { id: 1, text: 'Buy bread', done: false },
  { id: 2, text: 'Call Anna', done: false },
])
 
function removeTodo(id) {
  todos.value = todos.value.filter((todo) => todo.id !== id)
}
</script>
 
<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
      <button @click="removeTodo(todo.id)">Delete</button>
    </li>
  </ul>
</template>

The "Delete" button removes its own task: the handler receives the id from the current loop iteration.

Other sources

SyntaxWhat is looped over
v-for="todo in todos"Array items
v-for="n in 5"Numbers from 1 to 5
v-for="(value, key) in user"Values and keys of an object

A filtered list is rendered through computed from the computed properties lesson: v-for="todo in visibleTodos".

Common mistake

Putting v-if and v-for on the same element:

<li v-for="todo in todos" v-if="!todo.done" :key="todo.id">
  {{ todo.text }}
</li>

v-if runs before v-for, so the todo variable does not exist in it yet — Vue reports an error. Filter the list in computed, or move v-for to a template wrapper and keep v-if on li.

Thanks for reading!

Donate to the site — we work hard for you.