Reputation: 4533
I am trying to make component that needs object array to function. I am passing it from parent to child using props.
I am getting the data from API using axios.
Since the objects in the array may not contain required key "is_selected" then I am adding it to every object in array. But the problem is that the array is sometimes empty.
I have tried everything I could possibly find. The only way it works, is with static data.
I created sandbox also and there you can see in the console that the "COMPONENT DATA" is empty array for some reason but if you assign static objects to the array, it works flawlessly
So this is what I am doing in my child:
<template>
<ul>
<li v-for="item in items">{{item.title}}</li>
</ul>
</template>
<script>
export default {
props: {
items: {
type: Array,
default: []
}
},
data() {
return {
local_items: this.items
};
},
methods: {},
created() {
var result = this.local_items.map(function(el) {
var o = Object.assign({}, el);
o.is_selected = false;
return o;
});
this.local_items = result
console.log('COMPONENT DATA: ', this.local_items);
}
};
</script>
And this is the parent:
<template>
<test :items="items"></test>
</template>
<script>
import Test from "./Test";
import axios from 'axios'
export default {
data() {
return {
items: []
};
},
methods: {},
async created () {
try {
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
this.items = response.data
})
}catch (e){
console.log('ERROR: ', e)
}
},
components: {
Test
}
};
</script>
What I am doing wrong? Can anyone please lead me to the right track?
Edit: if you are looking this, the working example is in the sandbox
Upvotes: 1
Views: 3412
Reputation: 15230
Posting comment as answer
The problem here is that within your child component you only process your data once when the child component is created and the created lifecycle hook is called. That's cool as long as
the data is passed directly into the component while constructing it (i. e. it's 'hard coded', for instance when the markup is rendered on the server-side) and
the passed in data never changes.
But in most cases you'll either fetch the data dynamically via Ajax or it will change during the lifetime of the component (or both).
In your case, you fetch the data dynamically from a parent component and then pass it to your child component. But the logic to process it is only called once when the created
lifecycle event fires. So it won't affect your data
if the data is not yet available during the creation of the component (which is quite likely, because you can't predict when an Ajax call will be finished) or
if the data changes during the component's lifetime.
So instead of hooking into a fixed lifecycle event you could either
fire your own event from the parent as soon as it has fetched the data and hook into it from your child (which can get quite messy on a larger scale)
watch the child component's properties for changes and then do what's necessary
So basically, you just want to call your logic from a watch
-handler instead of the created
-handler:
<script>
export default {
props: {
items: {
type: Array,
default: []
}
},
data() {
return {
local_items: this.items
};
},
watch: {
/* this is called every time the items prop changes */
items: function() {
var result = this.local_items.map(function(el) {
var o = Object.assign({}, el);
o.is_selected = false;
return o;
});
this.local_items = result
console.log('COMPONENT DATA: ', this.local_items);
}
}
};
</script>
Upvotes: 1