quasar-ui-qcalendar
quasar-ui-qcalendar copied to clipboard
On the initial page load mouse events don't fire
The bug I have a quasar application where I need to use both QCalendarDay and QCalendarAgenda. On the initial page load, components seem to load just fine, visually it's ok but mouse events don't fire at all. The only error in the console I get is when I navigate to the page with my q-calendar components from some other pages. The error is:
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'offsetWidth') QTabs.js:181:1
This is the function on line 181 that causes the error:
My theory
I assume you use QTabs for changing calendar view and on navigation the function recalculateScroll()
is called before the component is mounted.
I use QTabs on another page in my application and don't get the same problem.
My component for q-calendar handling looks like this.
<template>
<div>
<QCalendarDay
v-if="selectedCalendar === 'day'"
ref="calendarDay"
v-model="selectedDate"
v-model:model-tasks="sessions"
:selected-start-end-dates="startEndDates"
:view="selectedView"
:weekdays="[1, 2, 3, 4, 5, 6, 0]"
:interval-minutes="15"
:interval-count="96"
:interval-height="15"
time-clicks-clamped
hour24Format
animated
bordered
hoverable
focusable
@click-date="onClickDate"
@click-time="onClickTime"
@mousedown-time="onMouseDownTime"
@mouseup-time="onMouseUpTime"
@mousemove-time="onMouseMoveTime"
>
</QCalendarDay>
<QCalendarAgenda
v-if="selectedCalendar === 'agenda'"
ref="calendarAgenda"
v-model="selectedDate"
v-model:model-tasks="sessions"
:view="selectedView"
:weekdays="[1, 2, 3, 4, 5, 6, 0]"
:left-column-options="trainersColumn"
:interval-minutes="15"
:interval-count="96"
:interval-height="15"
column-options-id="id"
column-options-label="label"
time-clicks-clamped
hour24Format
animated
bordered
hoverable
focusable
@click-date="onClickDate"
>
</QCalendarAgenda>
</div>
</template>
<script setup>
import {
defineProps,
defineEmits,
defineExpose,
computed,
ref,
watch,
} from "vue";
import { useI18n } from "vue-i18n";
import { useQuasar } from "quasar";
import { useMouse } from "src/composables/mouse";
import {
QCalendarDay,
QCalendarAgenda,
today,
getDateTime,
getDayTimeIdentifier,
} from "@quasar/quasar-ui-qcalendar/src/index.js";
import "@quasar/quasar-ui-qcalendar/src/QCalendarVariables.sass";
import "@quasar/quasar-ui-qcalendar/src/QCalendarTransitions.sass";
import "@quasar/quasar-ui-qcalendar/src/QCalendar.sass";
const props = defineProps({
selectedCalendar: {
type: String,
default: "day",
},
selectedView: {
type: String,
default: "week",
},
sessions: {
type: Array,
default: [],
},
startEndDates: Array,
});
const emit = defineEmits([
"requestCreateSession",
"update:startEndDates",
"update:selectedDate",
]);
// Stores
const q = useQuasar();
const { t } = useI18n();
// Composables
const { isLeftClick } = useMouse();
// Additional
const trainersColumn = [
{
id: "trainers",
label: t("sidebar.trainers"),
},
];
// Data
const sessions = computed(() => props.sessions);
const calendarDay = ref(null);
const calendarAgenda = ref(null);
const selectedDate = ref(today());
const anchorTimestamp = ref(null);
const endTimestamp = ref(null);
const mouseDown = ref(false);
const startEndDates = computed(() => {
const dates = [];
const anchorDayTimeIdentifier = !!anchorTimestamp.value
? getDayTimeIdentifier(anchorTimestamp.value)
: false;
const endDayTimeIdentifier = !!endTimestamp.value
? getDayTimeIdentifier(endTimestamp.value)
: false;
if (!!anchorDayTimeIdentifier && !!endDayTimeIdentifier) {
if (anchorDayTimeIdentifier <= endDayTimeIdentifier) {
dates.push(
getDateTime(anchorTimestamp.value),
getDateTime(endTimestamp.value)
);
} else {
dates.push(
getDateTime(endTimestamp.value),
getDateTime(anchorTimestamp.value)
);
}
}
return dates;
});
// Watchers
watch(startEndDates, (newDates, oldDates) => {
emit("update:startEndDates", startEndDates);
});
watch(selectedDate, (newDate, oldDate) => {
emit("update:selectedDate", newDate);
});
watch(calendarDay, () => {
console.log('calendarDay', calendarDay.value)
})
// Methods
const setToday = () => {
calendarDay.value.moveToToday();
calendarAgenda.value.moveToToday();
};
const setPrev = () => {
calendarDay.value.prev();
calendarAgenda.value.prev();
};
const setNext = () => {
calendarDay.value.next();
calendarAgenda.value.next();
};
const onClickDate = (data) => {
console.log("onClickDate", data);
};
const onClickTime = ({ scope }) => {
console.log("onClickTime", scope);
};
const onMouseDownTime = ({ scope, event }) => {
console.log("onMouseDownTime", { scope, event });
if (isLeftClick(event)) {
if (
anchorTimestamp.value !== null &&
endTimestamp.value !== null &&
getDateTime(anchorTimestamp.value) ===
getDateTime(endTimestamp.value)
) {
endTimestamp.value = scope.timestamp;
mouseDown.value = false;
}
mouseDown.value = true;
anchorTimestamp.value = scope.timestamp;
endTimestamp.value = scope.timestamp;
}
};
const onMouseUpTime = ({ scope, event }) => {
console.log("onMouseUpTime", { scope, event });
if (isLeftClick(event)) {
// mouse is up, capture last and cancel selection
endTimestamp.value = scope.timestamp;
mouseDown.value = false;
}
if (scope.timestamp.future) {
emit("requestCreateSession");
}
};
const onMouseMoveTime = ({ scope }) => {
if (!!mouseDown.value) {
endTimestamp.value = scope.timestamp;
}
};
defineExpose({
setToday,
setPrev,
setNext,
});
</script>
Please note that on calendar view change, ref value get changed and mouse events start to work but I expect them to work from the start. My default calendar mode is day. So when I change to agenda, agenda works. And when I change the mode back to day, day also start to work.
My setup:
- Vue3, script setup
- Quasar: ^2.6.0
- quasar-ui-qcalendar: ^4.0.0-beta.15
- vue-router: ^4.0.0
- vueRouterMode: history