I'm using Fullcalendar 5 timeGrid view and I'm trying to add the number of events of the day into each day header.
I saw we can use the dayHeaderContent like that
calendarOptions = {
dayHeaderContent({ date, text, view }) {
return text + ' suffix';
}
// ...
}
This adds ' suffix' after each day header.
We can access the events through the api, but the day header is called just once and before receiving the events from the sources.
One can call api.render() to trigger the day header rendering, but that means almost everything gets rendered twice. Additionally I don't see when render() could be called. From an event source callback, events seem not updated just after the successCallback.
Example:
calendarOptions = {
eventSources: [
{
id: 'time-entries',
events(fetchInfo, successCallback) {
const events = getTheEvents();
successCallback(events);
fcApi.render(); // dayHeaderContent still shows the previous events
},
},
],
// ...
}
How can I effectively show the number of events on each day header ?
Related
I have an event on one calendar, and I need to offer the user the ability to move that event to another month in the same calendar. It seems like the best way to do this is (1) remove the event from the current calendar, (2) create a draggable div outside the calendar, (3) allow the user to change the month/day/year, (4) allow the user to drag the div back onto the calendar, (5) hide the new div, (6) submit an ajax request to update the datasource, (7) delete the newly dropped event.
Attached are the code snippets used to do this.
My question: this seems very roundabout. Is there a better way?
// 1
reschedulingEvent = calendar.getEventById(....)
reschedulingEvent.remove()
// 2
rescheduledAppointment = new FullCalendar.Draggable(document.getElementById(
'rescheduled-appointment'), {
eventData: {
id: reschedulingEvent.id,
title: reschedulingEvent.title,
duration: "0:" + (reschedulingEvent.end - reschedulingEvent.start)/1000/60,
}
})
// 4
calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
editable: true,
droppable: true,
eventDrop: addEventToForm,
eventReceive: addEventToForm,
});
async function addEventToForm(info) {
if (!confirm("Would you like to reschedule this appointment")) return;
$(".rescheduled-appointment-div").hide() // 5
await axios.post(`/appointments/${info.event.id}`, {
start: info.event.start,
end: info.event.end,
}) // 6
calendar.refetchEvents()
calendar.getEventById(info.event.id).remove() // 7
My Calendar has a specific view : it shows 31 days (display 4 days before the current day, and 27 days after)
Therefore, I have a dynamic visibleRange for my view
let INIT = moment().subtract(4, 'days').format('YYYY-MM-DD');
let INIT_END = moment(INIT).add(31,'days').format('YYYY-MM-DD');
[...]
type: 'resourceTimeline',
visibleRange: {
start: INIT,
end: moment(INIT).add(31,'days').format('YYYY-MM-DD')
},
buttonText: '31 jours'
}
and previous/next don't seem to work when visibleRange is defined for a custom view.
I tried something involving jQuery and it mostly works, except you have to click first twice on prev/next to change the visibleRange (and you also have to click twice when you go from next to previous or vice-versa).
And I wanted for this :
calendar.setOption('visibleRange', {
start: INIT,
end: INIT_END
})
to work, but in my implementation, it only works once and when it's triggered, clicking on buttons doesn't work anymore.
You can find the code on this CodePen
Can you help me ?
Okay so a colleague of a colleague led me to the solution, thanks a lot to him.
Instead of using visibleRange and trying to manipulate FullCalendar's data with jQuery (very gross), I calculate the difference between my two moments in order to have a duration :
const INIT = moment().subtract(4, 'days');
const INIT_END = moment(INIT).add(31,'days');
let duration = INIT_END.diff(INIT, 'days')
Then I use this duration in the settings of my customView :
resourceTimelineRollingMonth: {
type: 'resourceTimeline',
duration: { days: duration },
buttonText: '31 jours'
}
and for my view to start 4 days before the current day, in the Calendar object, I set :
[...]
defaultDate: INIT.format('YYYY-MM-DD'),
[...]
Which now works flawlessly.
Whenever the user selects the calendar I need to go back to the server and refresh the data for the dates they have selected - so on next, prev, etc. buttons. I tested that the event source works if defined on the calendar - but defined this way does not get the events. How do I hook up the views, next, prev buttons with the ajax call?
viewRender: function(view, element) {
var eventSource = {
url: '/JVCalendar/GetJVCalendarEvents',
type: 'POST',
data: {
start: "01/01/2015",
end: "01/31/2015",
calendarId: "1"
},
error: function() {
alert('there was an error while fetching events!');
}
}
$('#calendar').fullCalendar('addEventSource', eventSource);
$('#calendar').fullCalendar('refetchEvents');
}
I'll add this as an answer since it's only mentioned in the comments. Credits go to #smcd. Finally found this after a lot of hassle.
fullCalendar already sends the start and end date by default. When looking in the network logs I can see the parameters being added automatically.
api/v1/schedulings/fullcalendar?start=2016-02-28&end=2016-04-10&_=1458223901062
I have FullCalendar installed and working great, pulling in courses from my database.
You can view different courses based on clicking a button that submits the page again but passes different criteria.
The Issue is that on reloading of the page and the new content it skips back to the current date which is rather annoying when when you are looking at courses 3 months into the future!!
Does anybody know how to make the calendar go back to the page you where on after you have refreshed the page???
I have a feeling it might be something to do with getdate as I got the following code to work but can't seem to pass the result back through the URL and into the calendar setup.
$('#my-button').click(function() {
var d = $('#calendar').fullCalendar('getDate');
alert("The current date of the calendar is " + d);
});
If you use jquery.cookie you can store the currently viewed date in a cookie for the page being viewed and use that value to set the defaultDate when the page reloads. Pass these in as options when you initialise your calendar:
defaultView: Cookies.get('fullCalendarCurrentView') || 'month',
defaultDate: Cookies.get('fullCalendarCurrentDate') || null,
viewRender: function(view) {
Cookies.set('fullCalendarCurrentView', view.name, {path: ''});
Cookies.set('fullCalendarCurrentDate', view.intervalStart.format(), {path: ''});
}
This code also saves the current view (e.g. month, day etc...)
I used a combination of the two above. I set the localStorage value for the start date when creating, moving, or resizing an event as well as viewRender and then assigned that value to the defaultDate.
defaultDate: localStorage.getItem('Default_FullCalendar_Date'),
viewRender: function(view) {
localStorage.setItem('Default_FullCalendar_View', view.name);
...
},
select: function(start, due){
localStorage.setItem('Default_FullCalendar_View', start);
...
},
eventDrop: function(event, delta, revertFunc, jsEvent, ui, view){
localStorage.setItem('Default_FullCalendar_View', event._start._d);
...
},
eventResize: function(event, delta, revertFunc, jsEvent, ui, view){
localStorage.setItem('Default_FullCalendar_View', event._start._d);
...
}
Works like a charm.
You can use gotoDate method:
var d = $('#calendar').fullCalendar('getDate');
$('#calencar').fullCalendar( 'gotoDate', d.getFullYear(), d.getMonth(), d.getDate() )
Here is an updated answer for version 4 and 5 of fullcalendar.
since viewRender is no longer an option in these versions. I came up with a different approach using the loading option.
The loading option will give you a boolean argument stating whether the calendar is done loading or not. Inside that function I check if the calendar is done loading and if so, I set the calendar date to localStorage. Next I created an if else statement before the fullcalendar object to check if the localstorage item exists, and if so I set the defaultDate option in the calendar object to to localStorage date; if not, I just set it to today's date.
Example:
let viewDate;
const savedDate = localStorage.getItem("calDate");
if (savedDate !== null) {
viewDate = new Date(savedDate);
} else {
viewDate = today();
}
const calendarElement = document.getElementById('your_calendar');
const calendar = new FullCalendar.Calendar(calendarElement, {
defaultDate: viewDate,
loading: function(stillLoading) {
if (stillLoading === false) {
// When Calendar is done loading....
localStorage.setItem("calDate", calendar.getDate());
}
},
});
FullCalendar is working great apart from 1 issue I'm having.
The monthview div which loads a calendar in monthview mode, seems to show duplicate holidays loaded in. This happens when I add an event, and then call my calendar bind function, which basically runs the code below.
Has anyone else had a similar issue? It looks like 'removeEvents' function is working ok against the data feed which comes from an internal database, but seems to leave the google dates. When the addEventSource is called, it's adding the same events again.
var googleUkHolidaysFeed = {
url: 'http://www.google.com/calendar/feeds/uk__en%40holiday.calendar.google.com/public/basic',
cache: true,
color: "green"
};
$.getJSON(url, {}, function (data) {
$('#dayview').fullCalendar('removeEvents');
$('#dayview').fullCalendar('addEventSource', data);
if ($("#monthview")[0]) {
$('#monthview').fullCalendar('removeEvents');
$('#monthview').fullCalendar('addEventSource', data);
$('#monthview').fullCalendar('addEventSource', googleUkHolidaysFeed);
}
});
I resolved this issue myself. The 'removeEvents' has to be called followed by 'removeEventSource' like so:
('data' is json array of events provided by the app, 'googleCalendarUkHolidayFeed' is the url feed from google).
var googleCalendarUkHolidayFeed = {
url: "http://www.google.com/calendar/feeds/bla..."
}
$('#dayview').fullCalendar('removeEvents');
$('#dayview').fullCalendar('addEventSource', data);
if ($("#monthview")[0]) {
// remove events and re-add event source to reflect search/non-search
$('#monthview').fullCalendar('removeEvents');
$('#monthview').fullCalendar('removeEventSource', googleCalendarUkHolidayFeed);
$('#monthview').fullCalendar('removeEventSource', data);
$('#monthview').fullCalendar('addEventSource', googleCalendarUkHolidayFeed);
$('#monthview').fullCalendar('addEventSource', data);
}