Iteration - sikaeducation/vue-curriculum GitHub Wiki

Iteration in templates is achieved through the v-for directive:

<template>
  <ul>
    <li
      v-for="item in list"
      :key="item.id"
    >{{ item.content }}</li>
  </ul>
</template>

The syntax is similar to JavaScript's for..in statement. Some notes:

  • You must include the :key binding, which needs to be set to some unique value. IDs are a natural choice, but in the absence of an available ID any unique attribute will do.
  • If you also need the index, you can get it like so: v-for="(index, item) in list"
  • The item and the index in a v-for are scoped to the element you put the directive on and anything inside of them

Common Patterns

Including a default option

You can also hard-code items in a list, including multiple lists, etc. This is especially common for making disabled defaults in drop-downs or separators:

<template>
  <select>
    <option disabled>Please select an option below:</option>
    <option disabled>North America</option>
    <option v-for="countries in northAmericanCountries" :key="country.code">{{ country.name }}</option>
    <option disabled>Europe</option>
    <option v-for="countries in europeanCountries" :key="country.code">{{ country.name }}</option>
  </select>
</template>

Look out

Don't use the index as the key

It may be tempting to make the key the index:

<li v-for="(item, index) in list" :key="index"></li>

This doesn't work. Don't do it. Vue uses these keys to figure out which items to re-render, and it can't do that if the key is generated by the looping mechanism itself.

Make sure the :key is bound

It's easy to forget the binding in the template:

<li v-for="item in list" key="item.id"> // No!
<li v-for="item in list" :key="item.id"> // Yes!

If you leave off the :, you'll set the key to the static string "item.id", which is not what you're looking for.

Don't combine v-if and v-for

The same element should never have a v-if and a v-for:

<template>
  <ul>
    <li
      v-for="item in list"
      :key="item.id"
      v-if="list.length > 0"
    >{{ item.text }}</li>
  <ul>
</template>

Instead, try to split them up:

<template>
  <ul v-if="list.length > 0">
    <li
      v-for="item in list"
      :key="item.id"
    >{{ item.text }}</li>
  <ul>
</template>

Or use a computed property to make a custom list:

<template>
  <ul>
    <li
      v-for="item in activeList"
      :key="item.id"
    >{{ item.text }}</li>
  <ul>
</template>

<script>
export default {
  computed: {
    list() {
      return [...]
    },
    activeList() {
      return this.list.filter(item => item.isActive)
    },
  },
}
</script>

Exercises

Using this array:

[{
  id: 1,
  label: "Apple",
},{
  id: 2,
  label: "Banana",
},{
  id: 3,
  label: "Carrot",
}]

Render each one in a list item.

References

⚠️ **GitHub.com Fallback** ⚠️