Home > Software engineering >  When data is changed within the watch function, dom does not update
When data is changed within the watch function, dom does not update

Time:12-09

Below is the data in a component

data: function () {
      return {
        sltAreaStyle: {
          paddingTop: "3%",
        },
        checkedTypes: ["krw", "btc", "usdt"],
      };
    },

Below is watch function of checkedTypes data

watch: {
      checkedTypes: {
        handler: function (newVal, oldVal) {
          if (newVal.length < 1) {
              alert("Choose one or more.");
              var last = oldVal[0];
              this.$data.checkedTypes = [last];
            
          }
        },
      },
    },

Below is my html template

<div >
        <input type="checkbox" value="krw" v-model="checkedTypes">KRW</input>
        <input type="checkbox" value="btc" v-model="checkedTypes">BTC</input>
        <input type="checkbox" value="usdt" v-model="checkedTypes">USDT</input>
      </div>

I want to change the last value to checkedTypes data when all the check boxes are unchecked. If the first checkbox was finally unchecked, the checkedTypes would be 'krw' like checkedTypes = ['krw'] The checkedTypes data is ['krw'], but all checkbox tags are unchecked. That is, dom has not been updated. I don't think I understand Vue's life cycle well. I think this problem is related to the life cycle of v-model and components, but I don't know what the problem is. Please explain why this problem occurs and tell me how to solve it.

CodePudding user response:

Well this is more about Vue rendering mechanisms for v-modeleld input controls.

Check this:

  1. Only one last checkbox is checked so model value is ['krw']
  2. Uncheck last checkbox
  3. Watcher is executed - new model value is [] BUT the watcher immediately sets it to same value as before ... ['krw']
  4. Vue re renders the template (see the message in the console) BUT as the v-model value is same as during last render, it does not update the checkbox

Simple solution to situations like this is to postpone the update to next rendering cycle using nextTick

this.$nextTick(() => {
  this.checkedTypes = [last];
})

new Vue({
  el: "#app",
  data: function () {
    return {
      checkedTypes: ["krw", "btc", "usdt"],
    };
  },
  updated() {
    console.log("Component updated")
  },
  watch: {
    checkedTypes: {      
      handler: function (newVal, oldVal) {
        if (newVal.length < 1) {
          alert("Choose one or more.");
          //console.log("Choose one or more.");
          var last = oldVal[0];
          // this.checkedTypes = [last];
          
          this.$nextTick(() => {
            this.checkedTypes = [last];
          })
        }
      },
    },
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
  <input type="checkbox" value="krw" v-model="checkedTypes"/> KRW
  <input type="checkbox" value="btc" v-model="checkedTypes"/> BTC
  <input type="checkbox" value="usdt" v-model="checkedTypes"/> USDT
  
  <pre>{{ checkedTypes }}</pre>
</div>

  • Related