Reputation: 11114
I have a small code with FullCalendar library displaying 2 calendars. One on the first tab, one on the 2nd tab. Both calendars show up, however, the one that is invisible when the page loads is not showing up properly.
Full code: https://codepen.io/MadBoyEvo/pen/rNxQQYP
So I thought I would do a refresh or quickly change the view from current to new one and back to current on a tab switch but whatever I do it doesn't work.
<script type="text/javascript">var tabs = tabbis.init({
tabGroup: "[data-tabs]",
paneGroup: "[data-panes]",
tabActive: "active",
paneActive: "active",
callback: function (tab, pane) {
// console.log("TAB id:" + tab.id);
// console.log(pane.id);
// console.log(tableid);
// this makes sure to refresh tables on tab change to make sure they have buttons and everything
// it's a bit heavy as it touches all tables, may require some improvements in future to consider
// which tab has which table
try {
var tableid = document.getElementById(tab.id + "-Content").querySelector('table[id^="DT-"]').id;
$("#" + tableid).DataTable().columns.adjust().responsive.recalc();
} catch (e) {
console.log('No datatables available.');
}
// this code here doesn't work
var view = $('#Calendar-on26xq0w').fullCalendar('getView');
alert("The view's title is " + view.title);
}
});
// in theory should take care of removing local storage for tabbis
// some errors occurs if the local storage is not cleaned after a while
window.addEventListener("unload", tabbis.remove, false);
</script><!-- JS Elastic Tabbis END -->
The error shows up: Uncaught TypeError: $(...).fullCalendar is not a function
I tried moving calendar.js script from top to bottom, to before or after the script code that fails but nothing is helping.
I am a bit of JS noob so it's a bit unclear to me why it doesn't work. I used similar approach for DataTables (the Try/catch) and it works fine (if there is DataTable loaded)
Edit:
I've tried searching for calendar id - and I can find it, yet the same error is visible on that 3rd line.
var calendarid = document.getElementById(tab.id + "-Content").querySelector('div[id^="Calendar-"]').id;
alert("The calendarid " + calendarid);
var view = $('#' + calendarid).fullCalendar('getView');
alert("The view's title is " + view.title);
Upvotes: 0
Views: 4042
Reputation: 11114
Thanks to @ADyson from comments I was able to understand my issues:
If you're using fullcalendar v5 as per your tag, then $('#Calendar-on26xq0w').fullCalendar will never work - that's the syntax from fullCalendar v3 (back when it was a jQuery plugin, hence the jQuery-style selector to initialise the object). If you want to call a method in v4 or v5 then you need a reference to the object you created when initialising the calendar, and then to get the current view you can simply write calendar.view (it's a property not a function) - see fullcalendar.io/docs/Calendar-view . (There's no such function as getView in v5 either.)
At the very top defined empty object
<!-- JS FullCalendar Basic START -->
<script type="text/javascript">var calendarTracker = {
};
</script><!-- JS FullCalendar Basic END -->
<!-- CSS FullCalendar Basic START -->
Next for each calendar that I created
<script>document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('Calendar-c43nxqpi');
var calendar = new FullCalendar.Calendar(calendarEl,
{
"headerToolbar": {
"left": "prev,next,today",
"right": "dayGridMonth,timeGridWeek,timeGridDay,listMonth",
"center": "title"
},
"initialView": "listWeek",
"initialDate": "2020-07-20",
"nowIndicator": true,
"navLinks": true,
"businessHours": false,
"editable": false,
"events": [
{
"title": "Active Directory Meeting",
"description": "We will talk about stuff",
"start": "2020-07-20T11:43:35"
},
{
"title": "Lunch",
"description": "Very long lunch",
"start": "2020-07-22T08:43:35",
"end": "2020-07-23T11:43:35"
}
],
"dayMaxEventRows": true,
"weekNumbers": true,
"weekNumberCalculation": "ISO",
"selectable": true,
"selectMirror": true,
"buttonIcons": false,
"views": {
"listWeek": {
"buttonText": "list week"
},
"listMonth": {
"buttonText": "list month"
},
"listDay": {
"buttonText": "list day"
}
},
eventRender: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
}
);
calendar.render();
calendarTracker['Calendar-c43nxqpi'] = calendar;
});
</script>
I've stored this calendar object with key based on it's html id.
calendarTracker['Calendar-c43nxqpi'] = calendar;
Finally on tab switch
<script type="text/javascript">var tabs = tabbis.init({
tabGroup: "[data-tabs]",
paneGroup: "[data-panes]",
tabActive: "active",
paneActive: "active",
callback: function (tab, pane) {
// We need to make same thing for calendar
function redrawCalendar(calendar) {
//console.log(calendarTracker[calendar.id].view);
calendarTracker[calendar.id].changeView(calendarTracker[calendar.id].view.type);
console.log('Redrawing view for' + calendar.id)
}
try {
var calendar = document.getElementById(tab.id + "-Content").querySelectorAll('div[id^="Calendar-"]');
calendar.forEach(redrawCalendar)
} catch (e) {
console.log('No calendars available.');
}
}
});
// in theory should take care of removing local storage for tabbis
// some errors occurs if the local storage is not cleaned after a while
window.addEventListener("unload", tabbis.remove, false);
</script>
I'm basically finding all calendars on the given tab using querySelectorAll
and then for each calendar on the tab I'm running redrawCalendar function which based on the HTML DOM ID finds the correct calendar object, and resets its view making sure the visual part is up and running again.
Upvotes: 2
Reputation: 4302
You can create a calendar2 on the fly when the user tries to switch to the next tab. Listen for the change event
on the tab
and initialize the second calendar based on the calendarID
.
var calendarid = document.getElementById(tab.id + "-Content").querySelector('div[id^="Calendar-"]').id;
// alert("The calendarid " + calendarid);
if(calendarid == 'Calendar-3fso0g65') {
loadCalendarFirst(calendarid);
} else {
loadCalendarSecond(calendarid);
}
I added the following two methods to call when needed
<script>
function loadCalendarFirst(claendarID) {
var calendarEl = document.getElementById(claendarID);
var calendar = new FullCalendar.Calendar(calendarEl,
{
"headerToolbar": {
"left": "prev,next,today",
"right": "dayGridMonth,timeGridWeek,timeGridDay,listMonth",
"center": "title"
},
"initialView": "listWeek",
"initialDate": "2020-07-19",
"nowIndicator": true,
"navLinks": true,
"businessHours": false,
"editable": false,
"events": [
{
"title": "Active Directory Meeting",
"description": "We will talk about stuff",
"start": "2020-07-19T10:07:02"
},
{
"title": "Lunch",
"description": "Very long lunch",
"start": "2020-07-21T07:07:02",
"end": "2020-07-22T10:07:02"
}
],
"dayMaxEventRows": true,
"weekNumbers": true,
"weekNumberCalculation": "ISO",
"selectable": true,
"selectMirror": true,
"buttonIcons": false,
"views": {
"listWeek": {
"buttonText": "list week"
},
"listMonth": {
"buttonText": "list month"
},
"listDay": {
"buttonText": "list day"
}
},
eventRender: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
}
);
calendar.render();
}
function loadCalendarSecond(calendarID) {
var calendarEl = document.getElementById(calendarID);
var calendar = new FullCalendar.Calendar(calendarEl,
{
"headerToolbar": {
"left": "prev,next,today",
"right": "dayGridMonth,timeGridWeek,timeGridDay,listMonth",
"center": "title"
},
"initialDate": "2020-07-19",
"nowIndicator": true,
"navLinks": true,
"businessHours": false,
"editable": false,
"events": [
{
"title": "Active Directory Meeting",
"description": "We will talk about stuff",
"start": "2020-07-19T10:07:02"
},
{
"title": "Lunch",
"description": "Very long lunch",
"start": "2020-07-21T07:07:02",
"end": "2020-07-22T10:07:02"
}
],
"dayMaxEventRows": true,
"weekNumbers": true,
"weekNumberCalculation": "ISO",
"selectable": true,
"selectMirror": true,
"buttonIcons": false,
"views": {
"listWeek": {
"buttonText": "list week"
},
"listMonth": {
"buttonText": "list month"
},
"listDay": {
"buttonText": "list day"
}
},
eventRender: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
}
);
calendar.render();
}
loadCalendarFirst('Calendar-3fso0g65');
</script>
Here's the Updated Plunker
Upvotes: 0
Reputation: 94
The error indicates that the element you try to run the fullCalendar()
function on is not available. This means that the HTML element with the ID Calendar-on26xq0w
can't be found on the document.
Upvotes: -1