4

I'm learning VueJs and I'm trying to figure out what's the best solution for my problem.
The problem is that if I call this.$set() multiple times, only the last call will be registered.

I have tried using setTimeout (like in old angular1 days), but it still doesn't work.
Then I tried with Vue.$nextTick() which should rerender the DOM, but it seems that the data is not added fast enough in the object.

Check demo here.
Press on every button multiple times and you'll see that the first log is skipped in the most of the time.

2 Answers 2

2

The use of Date.now() is not correct. it happens so fast, that the timestamp sometimes not changing between the 2 this.$set operations, so you override the value in logs object.

see the logs of Date.now() when i click the first button

 1509287060410 // first result of Date.now.
 1509287060412 // Second Result of Date.now - this time, it's different from the first attempt, so 2 different entries will be created.
 1509287061243 // another click on the button - timestamp has changed obviosuly.
 1509287061243 // Javascript did the second Set so far, that time timestamp didn't even changed yet. thus, it overrides the value of the second entry

so this log, the result of 4 this.$set operations, created this logs object:

{
    1509287060410:"I was clicked!"
    1509287060412:"I was clicked again!"
    1509287061243:"I was clicked again!"
}

The last 1509287061243 property was overrriden.

You have to ensure that the key of this.$set (second argument of the function) is different every time you call it.

See my new code suggestion:

  data() {
    return {
      title: 'Multiple Vue.set() not updating object/DOM',
      logs: {},
      index: 0
    }
  },
  methods: {
    log: function(data) {
      console.log(Date.now())
      this.index += 1
      this.$set(this.logs, this.index, data)
    },
Sign up to request clarification or add additional context in comments.

1 Comment

Wow, I have never ever thought about the fact that I might override the key! Doing this inside a framework, really makes you think just about it and pushing away the basics. I was only thinking that this is the same thing I was facing in the Angular world. Thank you!
1

You can also change the logs type to Array. This way you won't miss any log due to key override. For example,

new Vue({
  el: '#app',
  data() {
    return {
      logs: []
    }
  },
  methods: {
    log(data) {
      this.logs.push({
        time: Date.now(),
        text: data
      })
    },
    logClick() {
      this.log('I was clicked!')
      this.log('I was clicked again!')
    }
  }
})
<div id="app">
  <button @click="logClick">Log click :)</button>
  <ul v-if="logs">
    <li v-for="(log, i) in logs" :key="i" v-text="log.text"></li>
  </ul>
</div>
<script src="https://unpkg.com/vue"></script>

1 Comment

I know about this, but I wanted to know why it doesn't work with object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.