'Delay' in the assignment / existence of properties in the instance vue

2

I have the following code:

Vue.component('child-comp', {
  template: '<p>Child here</p>',
  props: ['item'],
  methods: {
     alt: function(msg) {
    	alert(msg);
     }
  }
});

new Vue({
  el: '#app',
  data() {
     return {
        item: null
     }
  },
  methods: {
     load_child: function() {
        this.item = true;
        this.$refs['comp1'].alt(this.item.toString());
     }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script><divid="app">
  <button v-on:click="load_child">execute child</button>
  <child-comp v-bind:item="item" v-if="item != null" ref="comp1"></child-comp>
</div>

As you can see the first click gives error, saying:

  

Can not read property 'alt' of undefined / TypeError: this. $ refs.comp1 is undefined

When in the previous line this component ( this.item = true; ) should already exist defined

To get around this I did:

Vue.component('child-comp', {
  template: '<p>Child here</p>',
  props: ['item'],
  methods: {
     alt: function(msg) {
    	alert(msg);
     }
  }
});

new Vue({
  el: '#app',
  data() {
    return {
        item: null
    }
  },
  methods: {
     load_child: function() {
        this.item = true;
        setTimeout(() => {this.$refs['comp1'].alt(this.item.toString());}, 100);
     }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script><divid="app">
  <button v-on:click="load_child">execute child</button>
  <child-comp v-bind:item="item" v-if="item != null" ref="comp1"></child-comp>
</div>

But I do not want or even seem at all to be the right one.

I'm looking for an alternative to this, have I implemented anything wrong, or should have done something I did not know / exist.

    
asked by anonymous 24.10.2017 / 15:41

2 answers

2

In similar cases I usually use arrays, passing content by props , and displaying the elements in the DOM depending on that array. So everything is sequential, without possible race conditions.

Vue.component('child-comp', {
  template: '<div><h3>{{item.title}}</h3><p>{{item.body}}</p></div>',
  props: ['item']
});
const url = 'https://jsonplaceholder.typicode.com/posts/';
new Vue({
  el: '#app',
  data() {
    return {
      items: [],
      postNr: 1
    }
  },
  methods: {
    load_child: function() {
      axios.get(url + this.postNr++)
        .then(res => this.items.push(res.data))
        .catch(e => console.log(e));
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.0/axios.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>



<div id="app">
  <button v-on:click="load_child">load post</button>
  <child-comp :item="item" :key="item.id" v-for="item in items"></child-comp>
</div>
    
24.10.2017 / 16:58
2

What is happening is that you should wait for the DOM to change, because the value you need is in it. Vuejs has the solution for these types of behavior, it is nextTick . This command is to wait for the DOM change after the above code and as soon as the DOM is changed, it will be executed. See this documentation to learn more.

Vue.component('child-comp', {
  template: '<p>Child here</p>',
  props: ['item'],
  methods: {
    alt: function() {
      alert(this.item);
    }
  }
});

new Vue({
  el: '#app',
  data() {
    return {
      item: null
    }
  },
  methods: {
    load_child: function() {
      this.item = true;

      // LINHA ADICIONADA
      this.$nextTick(function() {
        this.$refs['comp1'].alt();
      });

    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script><divid="app">
  <button v-on:click="load_child">execute child</button>
  <child-comp v-bind:item="item" v-if="item != null" ref="comp1"></child-comp>
</div>
    
24.10.2017 / 15:48