Andreas Hunter
Andreas Hunter

Reputation: 5004

Vue.js - template doesn't update when variable value change

I have like this action in my app where I manupulate data inside created hook:

HTML template example:

<template>
  <div>
    <p v-for="item in items" :key="item.id">{{ item.title }}</p>
  </div>
</template>

Note: As template in my app I use vue grid layout package really

Working code:

created () {
  if(Array.isArray(this.predefinedItems)) {
    for (let index = 0; index < this.predefinedItems.length; index++) {
      this.items[index] = {...this.predefinedItems[index], ...{
        i: index, x: 1, y: 1, w: 12, h: 8, accent: 'info'
      }}
    }
    console.log(this.items)
  }
}

Not working code:

created() {
  this.emulateApiRequest()
}

methods: {
  emulateApiRequest() {
    setTimeout(() => {
      if (Array.isArray(this.predefinedItems)) {
        for (let index = 0; index < this.predefinedItems.length; index++) {
          this.items[index] = {
            ...this.predefinedItems[index],
            ...{ i: index, x: 1, y: 1, w: 12, h: 8, accent: 'info'
            }
          }
        }
        console.log(this.items)
      }
    }, 500)
  },
}

Why my template not updates when I emulate api request to set data?

Upvotes: 1

Views: 1424

Answers (1)

tony19
tony19

Reputation: 138246

The problem is you're editing items[] by index directly, which cannot be automatically detected in Vue 2. The first example only works because the created() hook occurs before the template is evaluated. The second example asynchronously updates items[], occuring after the created() hook and after the template has been evaluated.

However, Vue 2 can detect Array.prototype.push() for item insertion into an array:

for (let index = 0; index < this.predefinedItems.length; index++) {
  // this.items[index] = /*...*/
  this.items.push(/*...*/)
}

demo

Alternatively, you could set items[] to a new array instance:

const items = []
for (let index = 0; index < this.predefinedItems.length; index++) {
  items[index] = /*...*/
}
this.items = items

Or replace the for-loop with Array.prototype.map, mapping predefinedItems into a new array:

this.items = this.predefinedItems.map(item => ({
  ...item,
  i: index, x: 1, y: 1, w: 12, h: 8, accent: 'info'
}))

Upvotes: 2

Related Questions