[Vuejs]-Notify vue that item internal has been changed

0👍

The problem is v2 property of _data. v2, specifically, is not reactive.

Official docs – Change Detection Caveats:

Due to the limitations of modern JavaScript (and the abandonment of Object.observe), Vue cannot detect property addition or deletion.

To work around it, you can either declare it in the constructor (this option works best when you know what properties you’ll have):

  constructor(v1) {
    this._data = {
      v1,
      v2: null  // <========= added this
    };
  }
class C {
  constructor(v1) {
    this._data = {
      v1,
      v2: null  // <========= added this
    };
  }

  addV2(v2) {
    this._data['v2'] = v2;
    alert( 'Item is fully loaded' );
    console.log(this._data);
  }

  get value1() {
    return this._data.v1;
  }

  get value2() {
    if ('v2' in this._data) {
      return this._data.v2;
    }

    return;
  }
}

new Vue({
  el: '#app',
  template: `
  <div>
     <div>
            {{item.value1}}, {{item.value2}}
            <button @click="fullLoad">+</button>
        </div>
  </div>`,
  data: {
    item: new C(0)
  },
  methods: {
    fullLoad() {
      this.item.addV2(2 * Math.random());
      
      // How to notify vue about changes here?
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app"></div>

Or change it using Vue.set(). (This option works best for the general case.)

  addV2(v2) {
    Vue.set(this._data, 'v2', v2);    // <========= changed here
    alert( 'Item is fully loaded' );
    console.log(this._data);
  }
class C {
  constructor(v1) {
    this._data = {
      v1
    };
  }

  addV2(v2) {
    Vue.set(this._data, 'v2', v2);    // <========= changed here
    alert( 'Item is fully loaded' );
    console.log(this._data);
  }

  get value1() {
    return this._data.v1;
  }

  get value2() {
    if ('v2' in this._data) {
      return this._data.v2;
    }

    return;
  }
}

new Vue({
  el: '#app',
  template: `
  <div>
     <div>
            {{item.value1}}, {{item.value2}}
            <button @click="fullLoad">+</button>
        </div>
  </div>`,
  data: {
    item: new C(0)
  },
  methods: {
    fullLoad() {
      this.item.addV2(2 * Math.random());
      
      // How to notify vue about changes here?
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app"></div>

No access to the third-party class code

If you have no access to C class internals, you can re-add the item data property, as below:

  methods: {
    fullLoad() {
      let i = this.item;                                  // save for reinsertion
      this.item = null;                                   // remove
      Vue.set(this, 'item', i);                           // reinsert as fully reactive
      
      this.item.addV2(2 * Math.random());
    }
  }

Runnable demo:

class C {
  constructor(v1) {
    this._data = {
      v1
    };
  }

  addV2(v2) {
    this._data['v2'] = v2;
    alert( 'Item is fully loaded' );
    console.log(this._data);
  }

  get value1() {
    return this._data.v1;
  }

  get value2() {
    if ('v2' in this._data) {
      return this._data.v2;
    }

    return;
  }
}

new Vue({
  el: '#app',
  template: `
  <div>
     <div>
            {{item.value1}}, {{item.value2}}
            <button @click="fullLoad">+</button>
        </div>
  </div>`,
  data: {
    item: new C(0)
  },
  methods: {
    fullLoad() {
      let i = this.item;                                  // save for reinsertion
      this.item = null;                                   // remove
      Vue.set(this, 'item', i);                           // reinsert as fully reactive
      
      this.item.addV2(2 * Math.random());
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app"></div>

Leave a comment