List of Objects Not Rendering in v-for loop in Vue with Array
Sorry for the novel, but I want to make sure I give enough info. I've read the Vue reactivity docs and I'm not adding elements by index or changing the length of the array, but I'm still having problems with my component not updating properly. I'm just doing a plain assignment with my array. I've made it so you can drag and drop the goals in order to have them in whatever order you want, save the order, and reload them in the correct order.
What happens is most of the time, it doesn't render at all. If I change a prop in the element with v-for in the template and save (like, switching ":key="goal.id" to :key="goal.title" or vice versa), forcing a refresh, it will render one time correctly and then disappear after I click on saveGoals(). saveGoals() still works correctly and saves the goals in the right order. Array is being repopulated after saveGoals() to make sure I'm getting the new order of the goals. No errors are appearing in the console. Reloading the page doesn't work, only changing the prop value.
It used to consistently render just fine, but unfortunately, I can't remember what code I changed to break it. The onMounted() function (using the composition API) is using DB functions, and after extensive testing, I verified that the DB functions are working correctly. I removed the draggable library for testing purposes and found that I encounter the same error. It seems to be working fine with a hardcoded list, however, I haven't tested any save function with the hardcoded list. I've tried it with different lifecycle hooks (onBeforeMounted, onCreated, etc.) and I got the same result.
It is being rendered using <component :is="GoalList"> because there's three components on the page (think tabs). Switching between the components doesn't update it, either, but switching between the components also doesn't make anything disappear.
I don't know why I have to force a refresh by changing a prop on an element, but that's the only thing that seems to work. I'd rather not write a hack to force the refresh (creating a key that updates with a counter function), but if that's the only fix I'll take it. As far as I can tell, it should be rendering the array just fine.
EDIT: A simplified version of the code can be found here: Codesandox.io link. Everything works fine in the sandbox, so there's something in the original code. DB is returning the array just fine, and since everything was working I added in vue-draggable-next and Element+ to try to isolate the issue with no luck.
EDIT: I managed to clarify the issue. Sorry for the long posts.
Upon initially loading, even though there's data in the array, nothing is loaded on the page. If I change the template code in any way (adding a button, changing a prop, removing a button, etc.) and save the Vue file, the content appears.
Tried clearing out the cache on my browser in case there was something there causing the issue. Also tested on multiple browsers.
A hardcoded list works as expected: it renders upon page load just fine. To ensure that I wasn't trying to loop a blank array, I added a logging button that logs out the array to the console. The array is populated with the data.
What makes me think that I'm breaking the renderer somehow is that everything populates when the template code is updated and npm run serve refreshes. Everything works perfectly. It's just blank on the initial page load (and, of course, when reloaded).
I honestly don't even know where to start with debugging this issue, which is probably why I'm having a problem explaining it. Not expecting a magical fix, just a direction to head in.
Onto the code. If you think the DB code would be helpful, I am happy to add it, although it is ugly:
Template:
<template>
<h2>Your Goals</h2>
<el-form @submit.prevent>
<draggable v-model="goals">
<div v-for="goal in goals" :key="goal.id">
<el-card class="box-card">
<div class="goal_header">
<h3></h3>
</div>
<div class="goal_buttons">
<el-button @click="deleteGoal(goal.id)" type="danger"
>Delete Goal</el-button
>
<el-button @click="editGoal(goal.id)">Edit Goal</el-button>
</div>
</el-card>
</div>
<el-button @click="saveGoals">Save Goals</el-button>
</draggable>
</el-form>
</template>
onMounted():
onMounted(() => {
getAuth().onAuthStateChanged((user) => {
if (user) {
try {
getOrderOfGoals(user.uid).then((result) => {
if (result.goalOrder.length === 0) {
getListOfGoals(user.uid).then((result) => {
goals.value = result;
console.log(goals.value);
});
} else {
returnOrderedGoals(user.uid, result.goalOrder).then(
(result) => {
goals.value = result;
});
}
});
} catch (error) {
ElMessageBox.alert(
"An error has occurred attempting to render the component. " +
error,
"Error",
{
confirmButtonText: "OK",
}
);
}
} else {
router.push("/");
}
});
});
saveGoals():
function saveGoals() {
getAuth().onAuthStateChanged((user) => {
if (user) {
try {
saveGoalOrder(user.uid, goals.value)
.then(() => {
getOrderOfGoals(user.uid)
.then((result) => {
returnOrderedGoals(user.uid, result.goalOrder).then(
(response) => {
goals.value = response;
}
);
})
...(A bunch of catches for Promises being thrown about).
from Recent Questions - Stack Overflow https://ift.tt/3wt13fA
https://ift.tt/eA8V8J
Comments
Post a Comment