I've working on a big application and I'm having a lot of trouble dealing with data from my API and passing it onto my child components.
The situation.
I'm calling my API from the parent component and passing the data through a prop to my child component. The child component displays the data just fine, but I'm not able to access the data within the ready function in my child component.
Take a look: https://jsfiddle.net/kmrfkynf/3/
As you can see in the console, displaying the data within the child components ready function gives me a empty object...
ready: function(){
console.log('items from child component', this.items);
}
... but the child components renders the object just fine within my repeat.
So the problem is that the child component is rendered before the API call from the parent is complete. When its complete, it syncs the data to my child component, thus rendering just fine.
What I've tried
Watching the prop from within my child component. When the prop is 'complete' I can access it. But this gives me lots of problems when trying to modify some data in the prop, because it renders every time. This is not the solution I want.
The question
How can I make sure that the prop is filled when the child component is ready?
The problem is that the DOM is loaded and ready while the AJAX function is still receiving the data. So the ready method on the component fires before the results come back from the server.
You could fire an event to tell the child when the data is back from the server:
var item = Vue.extend({
props: ['items'],
data:function(){return{items:[]}},
template: '<div v-for="item in items">{{ item }}</div>',
ready: function(){
this.$on('datahere', function(){
alert(this.items[0].id);
//console.log('datahere items', this.items);
})
//console.log('items from child component', this.items);
}
})
Vue.component('item', item);
var items = Vue.extend({
ready: function(){
this.init();
},
data: function(){
return {
items: {}
}
},
methods:{
init: function(){
this.getItems();
},
getItems: function(){
this.$http.get('https://api.github.com/users/mralexgray/repos')
.success(function(data){
this.$set('items', data);
this.$nextTick(function(){
this.$broadcast('datahere', data);
});
console.log('items from parent components: ', this.$get('items'));
})
}
},
template: '<div class="test"><item :items.sync="items"></item></test>',
components: {'item': item}
})
Vue.component('items', items);
var app = new Vue({
el: '#app'
})
As @Douglas.Sesar said, the ready
method on the item
component fires before the results come back from the server.
To fix that, all you need to add is the activate hook
:
var item = Vue.extend({
activate: function(done) {
var unwatch = this.$watch('items', function() {
unwatch(); // teardown the watcher
done(); // ready to insert the component
});
},
props: ['items'],
template: '<div v-for="item in items">{{ item }}</div>',
ready: function(){
console.log('items from child component', this.items);
}
})
That hook is called before component insertion. The component will not be inserted until the done
callback is called. The done
callback is called when the items
changed (see watch
for details). Hence, the items
will have the correct data when the ready
function is called.
https://jsfiddle.net/kmrfkynf/8/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With