Why Vue.js :class not working when it depends on list item property?

Viewed 278

I'll be short. Here is my html:

<tr v-for="product in products"
:class="{'bg-red': product.toWrite }" :key="product.name">
  <td @click="setObjectToWrite(product.name)" class="show-hover">
    <u>{{product.name}}</u>
  </td>
</tr>

@onclick handler:

  setObjectToWrite (name) {
    // this.products = []
    let products = this.products
    products.forEach(p => {
      if (p.name == name) {
        p.toWrite = true // ignores
        p.name+=' ' // now displays
      }
    })
    console.log('new products', products) // OK
    this.products = products
  },

So, the handler is working, I see that products array is updated - I see this in console. But the css is not changing. (If I change .name, css does diplay changes).

My products array initially looks like this: [{name: 'some name'},...]

I am confused. I think I misunderstood something.


Solved, thanks to @Ross Allen. To make it work, I need some minor changes:

setObjectToWrite (product) {
    let name = product.name
    let products = [...this.products] // we should treat data-props as immutable, if we need to add props to objects.
    products.forEach(p => {
    ...
1 Answers

If toWrite is a new property then Vue cannot detect its addition. See Vue reactitivy for objects: "Vue cannot detect property addition or deletion".

I suggest treating values in data as immutable, and for this case that would mean creating new objects whenever you need to add properties:

  setObjectToWrite (name) {
    const nextProducts = this.products.map(p => {
      if (p.name == name) {
        // Creates a new Object, Vue will see this and re-render
        return {
          ...p,
          toWrite: true,
        };
      } else {
        return p;
      }
    })
    this.products = nextProducts
  },
Related