Get 2024 Templates Mega Bundle!14 Bootstrap, Vue & React Templates + 3 Vector Sets
Get for 99$

Reactivity issue of FullCalendar in Drawer Component


Hello

I am working in a Vue 3 project that uses 8.1.6 Metronics version.

I need to display a FullCalendar Component in a "kt-drawer" Component but there is a reactivity issue and it seems that FullCalendar CSS (or maybe FullCalendar options ?) are not reactive so FullCalendar displays in this way when I click on "Dates" button :

https://a-p-c-t.fr/to-meet/fullCalendar-reactivity-issue.PNG

But if I did a code modification or I just display web browser inspector, FullCalendars is displayed correctly :

https://a-p-c-t.fr/to-meet/fullCalendar-ok.PNG

Kindly, could you check mon code et tell me how can I make reactive FullCalendar's Component ?


This is FullCalendar's Component code :

<script lang="ts">
import { defineComponent, reactive, ref, type PropType, toRef, watch, onBeforeMount, watchEffect } from 'vue';
import { Field, ErrorMessage, FieldArray } from "vee-validate";
import FullCalendar, { type CalendarOptions } from "@fullcalendar/vue3";
import OptionsServices from "./services";
import type { PollInterface } from '@/services/interfaces/pollInterfaces/poll.interfaces';
import { usePollStore } from '@/stores/_poll';
import { storeToRefs } from 'pinia';
import { useRoute } from 'vue-router';

export default defineComponent({
name: "create-form-dates",
components: {
FullCalendar,
Field,
ErrorMessage,
FieldArray
},
setup() {

const route = useRoute();
const pollStore = usePollStore()
pollStore.getPollById(route.params.id as string)
const poll = storeToRefs(usePollStore()).poll as unknown as PollInterface;

const optionsService = reactive(new OptionsServices());
const allEventsSlots = ref(optionsService.allEventsSlots);
const calendarEvents = reactive(optionsService.calendarEvents);
const options = reactive(optionsService.isCalendarOptions()) as unknown as CalendarOptions | undefined;

const eventCalendarRemove = reactive(optionsService.calendarOptions.eventClick);

const deleteCalendarEvent = (eventId:string) => {
const eventAPI = calendarEvents.find((e: { event: { _instance: { defId: string; }; }; }) => e.event._instance.defId === eventId)
return eventCalendarRemove(eventAPI)
}

return{
options,
allEventsSlots,
deleteCalendarEvent,
poll,
route
}
},
});
</script>
<template>
<div class="fv-row mb-10">
<i class="far fa-lightbulb text-primary me-2"></i>
<label class="form-label required">Choix des créneaux horaires</label>
<div :class="poll.id === route.params.id ? 'mx-auto mw-700px w-100 pt-15 pb-10' : 'd-block'">
<FullCalendar
class="mt-10 mb-10"
:options="options"
/>
<FieldArray name="calendarEvents"
>
<fieldset class="mt-5" v-for="(event, idx) in allEventsSlots"
:key="event.idEvent">
<div class="input-group">
<Field v-slot="{ field }"
:id="`date_${idx}`"
:modelValue="event.start + ` - ` + event.end"
:name="`date_${idx}`"
>
<input
v-bind="field"
:value="event.start + ` - ` + event.end"
class="form-control form-control-lg form-control-solid disable-input"
disabled
>
</Field>
<button type="button" @click="deleteCalendarEvent(event.idEvent)"
class="btn btn-primary"
>
<i class="bi bi-trash3"></i>
</button>
</div>
</fieldset>
<ErrorMessage
name="date_0"
class="fv-plugins-message-container invalid-feedback"
/>
</FieldArray>
</div>
</div>
</template>
<style lang="scss">
.fc-day-past {
background-color: rgb(233, 233, 233);
}
</style>

-------------------------------------------------------------------------------------

This is the "kt_drawer" component code :


<script lang="ts">
import { defineComponent } from "vue";
import Calendar from "@/app/pollCreation/components/step1/createDatesCalendar/index.vue";

export default defineComponent({
name: "add-date-question-drawer",
components: {
Calendar
},
});
</script>
<template>
<div
id="kt_dateQuestion"
class="bg-body"
data-kt-drawer="true"
data-kt-drawer-name="dateQuestion"
data-kt-drawer-activate="true"
data-kt-drawer-overlay="true"
data-kt-drawer-width="{default:'90%', 'lg': '50%'}"
data-kt-drawer-direction="end"
data-kt-drawer-toggle="#kt_dateQuestion_toggle"
data-kt-drawer-close="#kt_dateQuestion_close"
>
<div class="card w-100" id="kt_dateQuestion">
<div class="card-header pe-5" id="kt_dateQuestion_header">
<div class="card-title">
<div class="d-flex justify-content-center flex-column me-3">
<a
href="#"
class="fs-4 fw-bold text-gray-900 text-hover-primary me-1 mb-2 lh-1"
>Ajouter une nouvelle date</a
>
<div class="mb-0 lh-1">
<span
class="badge badge-success badge-circle w-10px h-10px me-1"
></span>
<span class="fs-7 fw-semobold text-gray-400">Active</span>
</div>
</div>
</div>
<div class="card-toolbar">
<button
type="button"
class="btn btn-sm btn-icon btn-active-light-primary me-n5"
id="kt_dateQuestion_close"
>
<span class="svg-icon svg-icon-1">
<inline-svg src="/media/icons/duotune/arrows/arr061.svg" />
</span>
</button>
</div>
</div>
<div class="card-body" id="kt_dateQuestion_body">
<Calendar />
</div>
<div class="card-footer pt-4" id="kt_dateQuestion_footer">
<div class="d-flex flex-stack">
<div class="d-flex align-items-center me-2">
<button
class="btn btn-sm btn-icon btn-active-light-primary me-1"
type="button"
data-bs-toggle="tooltip"
title="Coming soon"
>
<i class="bi bi-paperclip fs-3"></i>
</button>
<button
class="btn btn-sm btn-icon btn-active-light-primary me-1"
type="button"
data-bs-toggle="tooltip"
title="Coming soon"
>
<i class="bi bi-upload fs-3"></i>
</button>
</div>
<button
class="btn btn-primary"
type="button"
data-kt-element="send"
id="kt_dateQuestion_close"
>
Envoyer
</button>
</div>
</div>
</div>
</div>
</template>

--------------------------------------------------------------------------------

Thank you in advance.

Tania


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(

Replies (9)


Hi Tania,

Sorry for the late reply.

Your issue doesn't seem to be related to our drawer component.
Do you have the same problem when using a full calendar on vue-router page?

In your component, you have a custom Pania store and classes I assume that you are doing some asynchronous data fetch in there. I recommend testing the calendar with static data initially. Once the calendar functions with static data, you can then replace it with data from your server.

Explore examples of calendar usage in the official docs:
https://fullcalendar.io/docs/vue

Regards,
Lauris Stepanovs,
Keenthemes Support Team



Hello Lauris

Thanks for reply

Well I added static data to Calendar (the static data of original calendar of Metronic theme) and I also included Calendar's component in same button's page... it is displayed correctly but, it is not the case of same Calendar's component on the "kt-drawer" Component.

Please check this image :
https://a-p-c-t.fr/to-meet/events-from-core-data-.JPG

Maybe issue comes from Calendar's options service file ?

Kindly, could you check it ? :


import { reactive, ref } from "vue";
import moment from "moment";
import "moment/dist/locale/fr";
import frLocale from "@fullcalendar/core/locales/fr";
import "@fullcalendar/core/vdom";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import listPlugin from "@fullcalendar/list";
import interactionPlugin from "@fullcalendar/interaction";
import { todayDate, TODAY } from "@/app/pollCreation/allFakeData/eventsCal";
import type { Slot } from "@/services/interfaces/pollInterfaces/poll.interfaces";
import { elementEmitter } from "@/services/composables/eventEmitter"
import events from '../../../../../core/data/events';


export default class service {
allEventsSlots = ref<Slot[]>([]);
calendarEvents = reactive<any>([]);

getNewEvent = (e) => {
this.allEventsSlots.value.push(e);
};

getUpdateEvent = (x) => {
const response = this.allEventsSlots.value.findIndex((e) => e.idEvent === x.idEvent);
this.allEventsSlots.value.splice(response, 1, x); // splice : remplacer (il sert à update and delete) --> on récupre l'index, on splice un élément et on le remplace par x
elementEmitter.emitUpdate(this.allEventsSlots.value);
};

deleteEvent = reactive((a) => {
this.allEventsSlots.value.splice(
this.allEventsSlots.value.findIndex((e) => e.idEvent === a),
1
); // on recupere l'index et on splice 1 élément
this.calendarOptions.eventRemove;
elementEmitter.emitUpdate(this.allEventsSlots.value);
});

calendarOptions = reactive({
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
headerToolbar: {
left: "prev,next today",
center: "",
// right: "dayGridMonth,timeGridWeek,timeGridDay"
right: "title",
},
views: {
// dayGridMonth: { buttonText: "Mois" },
timeGridWeek: { buttonText: "Semaine" },
// timeGridDay: { buttonText: "Jours" },
},
initialView: "timeGridWeek",
locales: frLocale,
locale: "fr",
initialDate: TODAY,
firstDay: todayDate,
navLinks: true, // on peut cliquer sur les noms de jour/semaine pour naviguer dans les vues
selectable: true,
selectMirror: true,
events: events,
editable: true,
dayMaxEvents: true, // autoriser le lien "plus" lorsque trop d'événements
height:500,

selectAllow: (selectInfo) => {
// désactiver addEvent avant aujourd'hui
const beforeToday = todayDate.diff(selectInfo.start);
const noEventsBeforeToday = beforeToday <= 0;
return noEventsBeforeToday;
},

select: (calendarData) => {
const cal = calendarData.view.calendar;
cal.unselect();
cal.addEvent({
start: calendarData.start,
end: calendarData.end,
allDay: calendarData.allDay,
});
},

eventClick: (e) => {
const idEvent = e.event._instance.defId;
this.deleteEvent(idEvent);

e.event.remove();
},

eventAdd: (e) => {
this.calendarEvents.push(e)
const idEvent = e.event._instance.defId;
const start = moment(e.event.start).locale('fr').format("LLLL");
const end = moment(e.event.end).locale('fr').format("LLLL");

const newEvent = { idEvent, start, end };
this.getNewEvent(newEvent);

elementEmitter.emitUpdate(this.allEventsSlots.value);
},

eventChange: (e) => {
const idEvent = e.event._instance.defId;
const start = moment(e.event.start).locale('fr').format("LLLL");
const end = moment(e.event.end).locale('fr').format("LLLL");

const updateEvent = { idEvent, start, end };

this.getUpdateEvent(updateEvent);
},

eventRemove: (e) => {},
});

isCalendarOptions = () => {
return this.calendarOptions;
};
isallEventsSlots = () => {
return this.allEventsSlots
}
}


Thanks in advance for your help.

Tania



Hi Tania,

If the calendar functions correctly with static data, the issue is likely related to the structure of the response from your server. Please ensure that the object received from your servers matches the static object you pass into the calendar component.

Regards,
Lauris Stepanovs,
Keenthemes Support Team



Hello Lauris

I apologize, maybe I didn't explain myself correctly.

The issue is that Calendar on "kt-drawer" Component doesn't work with static data either.

On this image https://a-p-c-t.fr/to-meet/events-from-core-data-.JPG both Calendars are the same Calendar's Component

Kindly, check this video https://a-p-c-t.fr/to-meet/Calendar.webm

Thank you in advace for your help

Tania



Hi Tania,

Thank you for specifying this.

Are you using the same component on the page and in drawer?

Check if there are any errors in your console.

Regards,
Lauris Stepanovs,
Keenthemes Support Team



Lauris

Yes, I using the same component on the page and in drawer but just to show you the issue. In any case, the issue continues to appear in the drawer, removing the Calendar from the page.

I toke a look to browser's warnings (chrome and firefox)... there are not errors but a lot of warnings. I found two warnings regarding Calendar. Check this image https://a-p-c-t.fr/to-meet/carlendar-warnings.JPG

Here is the video of the console warnings https://a-p-c-t.fr/to-meet/Calendar-browser-warnings.webm

Thanks for your help.

Tania



Hi Tania,

Sorry for the delay in reply.

We've successfully reproduced this issue - there seems to be an issue with the full calendar render when used in our drawer.

While we investigate this further, as a temporary solution, you can force a rerender of the component by dispatching a resize event.


onMounted(() => {
nextTick(function () {
window.dispatchEvent(new Event("resize"));
});
});


Regards,
Lauris Stepanovs,
Keenthemes Support Team



Hello Lauris

Happy new year and thank you very much !
Calendar used in drawer works correctly.

Regards,
Tania



Hi Tania,

Happy New Year! I'm glad to hear it worked for you. If you have more questions on this topic or anything else, feel free to ask.

Regards,
Lauris Stepanovs,
Keenthemes Support Team


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(
Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(