I want to build a todo app with ionic-vue. It currently uses vue 3. I have this overview (called Lists.vue) where it is possible to click on multiple lists (where tasks should be loaded per list). However, everytime when I click on a list, the same data appears! It is as if the component is being reused but not re rendered/ updated.
I have tried all kinds of solutions. One of them was to apply a watch on the ref that is being changed, however, it does not matter, the end result stays the same. Also tried to give :key to router-link, still does not work.
My Lists.vue
<ion-page>
<ion-content v-if="chunk" class="flex flex-col overflow-auto ion-align-self-center content-wrapper">
<ion-toolbar class="mt-2">
<h1 class="text-4xl pl-5 font-semibold">Lijsten</h1>
</ion-toolbar>
<div v-for="(categoryChunk, index) in chunk.value" :key="index" class="flex flex-wrap w-full flex-row justify-around mt-2">
<div v-for="category in categoryChunk" :key="category.id">
<ion-card class='w-40 sm:w-80'>
<router-link :to="{ name: 'Index', params: {categoryId: category.id} }">
<ion-card-header class="flex">
<ion-icon class="mt-5 text-4xl" color="orange-secondary" :icon="allIcons[category.icon]"></ion-icon>
<div class="m-4">
<p><b>{{ category.title }}</b></p>
<p>Taken: {{ category.tasks }}</p>
</div>
</ion-card-header>
<ion-card-content><div class="line-vert"></div></ion-card-content>
</router-link>
</ion-card>
</div>
</div>
</ion-content>
<div v-else>
<ion-spinner class="centered" color="orange" name="crescent"></ion-spinner>
</div>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button color="orange-secondary" @click="setOpen(true)">
<ion-icon class="text-4xl" color="light" :icon="allIcons.add"></ion-icon>
</ion-fab-button>
</ion-fab>
<ion-modal
:is-open="isOpenRef"
css-class="my-custom-class"
>
<create-list v-on:on-close="setOpen(false)"></create-list>
</ion-modal>
</ion-page>
</template>
<script>
import { defineComponent, computed, ref, watch, onBeforeMount } from "vue";
import {
IonPage,
IonCard,
IonCardHeader,
IonIcon,
IonCardContent,
IonFab,
IonFabButton,
IonContent,
IonToolbar,
IonModal,
IonSpinner,
} from '@ionic/vue'
import * as allIcons from 'ionicons/icons'
import getCollection from "../../composables/getCollection"
import CreateList from './CreateList'
export default defineComponent ({
components: {
IonPage,
IonCard,
IonCardHeader,
IonIcon,
IonCardContent,
IonFab,
IonFabButton,
IonContent,
IonToolbar,
IonModal,
CreateList,
IonSpinner,
},
setup() {
const { loadCollection } = getCollection();
const chunk = ref()
// Zet modal open/dicht
const isOpenRef = ref(false);
const setOpen = (state) => isOpenRef.value = state;
// Laad alle categorieën uit de database
const reload = () => {
loadCollection('categories').then(data => {
chunk.value = computed(() => {
// Zet de items uit de database om in delen van twee.
const array = [];
const size = 2;
for(let i = 0; i < data.length; i += size) {
array.push(data.slice(i, i+size));
}
return array;
})
})
}
onBeforeMount(() => {
reload();
})
watch(isOpenRef, () =>{
reload()
})
return {
allIcons,
chunk,
isOpenRef,
setOpen,
}
}
})
</script>
My list called Index.vue (maybe I should just call it list.vue or something...)
<template>
<ion-page>
<ion-content v-if="category">
<ion-toolbar>
<div class="flex justify-between">
<h1 class="font-light pl-5">{{ category.title }}</h1>
<ion-icon class="text-2xl pr-5" :icon="closeOutline" @click="redirectBack()"></ion-icon>
</div>
</ion-toolbar>
{{ category }}
</ion-content>
<div v-else>
<ion-spinner class="centered" color="orange" name="crescent"></ion-spinner>
</div>
</ion-page>
</template>
<script>
import { defineComponent, ref } from "vue";
import { closeOutline } from 'ionicons/icons'
import {
IonPage,
IonContent,
IonToolbar,
IonIcon,
IonSpinner,
} from '@ionic/vue'
import { useRoute, useRouter } from "vue-router";
import getValue from "@/composables/getValue";
export default defineComponent ({
components: {
IonPage,
IonContent,
IonToolbar,
IonIcon,
IonSpinner
},
setup() {
const router = useRouter()
const route = useRoute()
const { loadValue } = getValue()
const category = ref()
// redirect terug naar lists indien men op kruisje klikt.
const redirectBack = () => {
return router.push({name: 'Lists'})
}
// Ophalen van data van een lijst.
loadValue('categories', route.params.categoryId).then(data => {
category.value = data
})
return {
closeOutline,
redirectBack,
category,
}
}
})
</script>
My composable function:
import {ref } from "@vue/reactivity";
import { todoFirestore } from "../firebase/config";
const getValue = () => {
const error = ref(null);
const loadValue = async (collectionName: string, id : string) => {
try {
let res = await todoFirestore.collection(collectionName).doc(id)
.get();
if (!res.exists) {
throw Error('Lijst bestaat niet.');
}
return { ...res.data(), id: res.id }
}
catch (err) {
error.value = err.message
}
}
return { error , loadValue }
}
export default getValue;
If someone knows any possible solutions, or what I'm possibly doing wrong, please help! All solutions are very appreciated.
PS: Due to circumstances, I am currently not able to reply very fast, but I assure you that I will reply to your answers :)