How to load different Event source (json) for each View? - fullcalendar

Hi i have a calendar which must load a different JSON source of events for each view. ie, A brief source for "Month" (only a max of 3 items per day cell), then more detailed sources of data for both "Day" and "Week".
I was thinking i could capture when a view has loaded and based on which view, call removeEventSource() to remove the previous event source then addEventSource() to add the current view's related data and refresh.
Is this the only way to do something like this? If so... how do i detect that the view has finished loading so i can call getView() to inturn load the appropriate event source?
I've seen there is loading() callback but i don't think this is what i need, i want to know when the whole calendar is complete loading not just the current data.
Thanks for any help
EDIT: The only other way I can think to do this is remove the DAY/WEEK/MONTH fullcalendar buttons and replace with my own which reloads the php screen with a variable appended say &calLoad=month or &calLoad=day i can then load with a different json feed but this is obviously a less optimal way of doing things.

Funnily enough I just posted an answer to an entirely different question that happens to be the solution to this. I used the addEventSource() and removeEventSource() methods, as the OP considered.
<script>
var fcSources = {
courses: {
url: base+'accessfm/calendar/courses',
type: 'GET',
cache: true,
error: function() { alert('something broke with courses...'); },
color: 'purple',
textColor: 'white',
className: 'course'
},
requests: {
url: base+'accessfm/calendar/requests',
type: 'GET',
cache: true,
error: function() { alert('something broke with requests...'); },
textColor: 'white',
className: 'requests'
},
loads: {
url: base+'accessfm/calendar/loads',
type: 'GET',
cache: true,
error: function() { alert('something broke with loads...'); },
color: 'blue',
textColor: 'white',
className: 'loads'
}
};
$('#fullcalendar').fullCalendar({
header: {
left: 'title',
center: 'agendaDay,agendaWeek,month',
right: 'today prev,next'
},
defaultView: 'agendaWeek',
firstDay: 1,
theme: true,
eventSources: [ fcSources.courses, fcSources.requests, fcSources.loads ],
viewDisplay: function(view) {
if (lastView != view.name){ // view has been changed, tweak settings
if (view.name == 'month'){
$('#fullcalendar').fullCalendar( 'removeEventSource', fcSources.loads )
.fullCalendar( 'refetchEvents' );;
}
if (view.name != 'month' && lastView == 'month'){
$('#fullcalendar').fullCalendar( 'addEventSource', fcSources.loads );
}
}
lastView = view.name;
}
});
</script>

viewDisplay is trggered when view has changed
http://arshaw.com/fullcalendar/docs/display/viewDisplay/
then you can check view.name atribute

Thank you for this example :)
I was not able to make this ( in above code the events array ) work for me, but i figure out another way to add event sources using some of the code you provided.
This is my logic:
My primary source of events is this(this is the events source from the default examples of Fullcalendar):
events: function(start, end, callback) {
$.ajax({
type: 'POST',
url: 'myurl',
dataType:'xml',
crossDomain: true,
data: {
// our hypothetical feed requires UNIX timestamps
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
'acc':'2',
},
success: function(doc) {
var events = [];
var allday = null; //Workaround
var Editable = null; //Workaround
$(doc).find('event').each(function()
{
if($(this).attr('allDay') == "false") //Workaround
allday = false; //Workaround
if($(this).attr('allDay') == "true") //Workaround
allday = true; //Workaround
if($(this).attr('editable') == "false") //Workaround
Editable = false; //Workaround
if($(this).attr('editable') == "true") //Workaround
Editable = true; //Workaround
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
allDay: allday,
editable: Editable
});
});
//calendar.fullCalendar( 'addEventSource', othersources.folgas );
//calendar.fullCalendar( 'addEventSource', othersources.ferias );
//calendar.fullCalendar('refetchEvents');
callback(events);
}
});
}
Now i needed it to add more sources and to do this ouside the calendar (next to the date variables from fullcalendar examples) i made a variable like the code above, but with ajax calls similar to my primary: )
var othersources = {
anothersource: {
events: function(start, end, callback) {
$.ajax({
type: 'POST',
url: 'myurl',
data: {
// our hypothetical feed requires UNIX timestamps
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
'acc':'7',
},
success: function(doc) {
var events = [];
var allday = null; //Workaround
var Editable = null; //Workaround
$(doc).find('event').each(function()
{
if($(this).attr('allDay') == "false") //Workaround
allday = false; //Workaround
if($(this).attr('allDay') == "true") //Workaround
allday = true; //Workaround
if($(this).attr('editable') == "false") //Workaround
Editable = false; //Workaround
if($(this).attr('editable') == "true") //Workaround
Editable = true; //Workaround
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
allDay: allday,
editable: Editable
});
});
callback(events); //notice this
}
});
},
cache: true,
//error: function() { alert('something broke with courses...'); },
color: 'green', //events color and stuff
textColor: 'white',
//className: 'course'
}
}
The following code is similar to the above and is part of the calendar proprietys (inside calendar variable):
eventSources: [ othersources.anothersource ],
viewDisplay: function(view) {
if (view.name == 'month'){
// alert(view.name);
//calendar.fullCalendar( 'addEventSource', othersources.folgas );
calendar.fullCalendar( 'addEventSource', othersources.anothersource );
//calendar.fullCalendar('refetchEvents'); //Notice i'm not doing the refetch events. And its working for me. but i'm calling thi elsewhere, every time i make an action. So you must figure it out ;)
}

Related

FullCalender 5 Unable to render dynamic events & resources

I am trying to render events and resources which are stored in a database. I can get the calendar to render with predefined data for events and resources, however when I push data into the array's, the new objects do not appear when the calendar is rendered.
This is the JS code I am using to obtain the data and render the calendar;
function GetCalenderDetails() {
$.ajax({
url: 'myapiendpoint',
type: 'GET',
success: function (response) {
$.each(response.bookedServices, function (i, v) {
services.push({
id: v.id,
title: v.title
});
});
console.log(JSON.stringify(services));
$.each(response.userBookings, function (i, v) {
bookings.push({
id: v.id,
resourceId: v.resourceId,
title: v.title,
start: v.start,
allDay: v.allDayFlag
});
});
console.log(JSON.stringify(bookings));
calendar.render();
},
error: function (error) {
console.log(error);
}
});
}
var bookings = new Array({ id: '1', resourceId: 'a', title: 'Meeting', start: '2021-03-14', allDay: true });
var services = new Array({ id: 'a', title: 'Room A' });
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
timeZone: 'UTC',
initialView: 'resourceTimelineDay',
aspectRatio: 1.5,
headerToolbar: {
left: 'prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth'
},
editable: true,
resourceAreaHeaderContent: 'Resources',
resources: services,
events: bookings
});
GetCalenderDetails();
The following is the console output of the 'services' and 'bookings' variables after the GetCalenderDetails function is executed;
Resources Output
[{"id":"a","title":"Room A"},{"id":"b","title":"Room B"}]
Events Output
[{"id":"1","resourceId":"a","title":"Meeting","start":"2021-03-14","allDay":true},
{"id":"2","resourceId":"b","title":"Meeting B","start":"2021-03-15","allDay":true}]
The first resource and event will render, however the second item which is pushed into the array from the GetCalenderDetails function do not render.
I am probably missing something very obvious, but I am not seeing it, so another set of eyes might help :)
As suggested by ADyson's comments, here is the solution to my problem just in case anyone else ends up in the same position;
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
timeZone: 'UTC',
initialView: 'resourceTimelineDay',
headerToolbar: {
left: 'prev,next,today',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth'
},
editable: true,
resourceAreaHeaderContent: 'Booked Services',
resources: function (info, successCallback, failureCallback) {
$.ajax({
url: 'myapiendpoint',
type: 'GET',
success: function (response) {
var resources = [];
console.log(response);
if (response.status == true) {
$.each(response.bookedServices, function (i, v) {
resources.push({
id: v.id,
title: v.title
});
});
} else {
//Do something
}
return successCallback(resources);
},
error: function (error) {
console.log(error);
}
});
},
events: function (info, successCallback, failureCallback) {
$.ajax({
url: 'myapiendpoint',
type: 'GET',
success: function (response) {
var events = [];
console.log(response);
if (response.status == true) {
$.each(response.userBookings, function (i, v) {
events.push({
id: v.id,
title: v.title,
start: v.start,
allDay: v.allDayFlag
});
});
} else {
//Do something
}
return successCallback(events);
},
error: function (error) {
console.log(error);
}
});
}
});
calendar.render();

Jquery full calendar (style changes after page refresh)

This is my calendar initially after the event creation:
and this is after page refresh:
Can anyone help me understand how to keep the same style even after page refresh, specifically the vertical line in the middle? Sometimes the line increases as well.
The fullCalendar JS is as follows:
$('#calendar').fullCalendar({
locale: 'nl',
weekends: true, // false will hide Saturdays and Sundays
defaultView: 'agendaWeek',
allDaySlot: false,
slotLabelFormat: "HH:mm",
axisFormat: 'HH:mm',
timeFormat: 'HH:mm',
aspectRatio: 1,
editable: true,
eventStartEditable: true,
selectable: true,
selectHelper: true,
unselectAuto: false,
eventLimit: true,
dragScroll: true,
eventOverlap: false,
slotEventOverlap: false,
header: {
left: 'title',
center: '',
right: 'prev,next,today,agendaWeek,agendaDay'
},
views: {},
eventDrop: function (event, dayDelta, minuteDelta, allDay, revertFunc) {
var title = "Available";
var eventInfo;
eventInfo = {
title: title,
start: event.start,
end: event.end,
id: event.id
};
updateEvent(eventInfo);
},
eventResize: function (event, dayDelta, minuteDelta, revertFunc) {
var title = "Available";
var eventInfo;
eventInfo = {
title: title,
start: event.start,
end: event.end,
id: event.id
};
updateEvent(eventInfo);
},
select: function (start, end) {
var title = "Available";
var eventData;
if (title) {
eventData = {
title: title,
start: start,
end: end
};
$('#calendar').fullCalendar('renderEvent', eventData, true); // stick? = true
createEvent(eventData);
}
$('#calendar').fullCalendar('unselect');
},
eventSources: [{
events: function (start, end, timezone, callback) {
var employeeId = $("#employee-Id").val();
$.ajax({
url: '../' + employeeId + '/events',
dataType: 'json',
success: function (response) {
var events = $.parseJSON(response.data);
$('#calendar').fullCalendar('addEventSource', events);
callback(events);
}
});
}
}],
eventRender: function (event, element) {
//delete event on double click..Tanvir
element.one().bind('dblclick', function (e) {
/* e.preventDefault();
$(this).prop('disabled', true);
setTimeout(function () { $(this).prop('disabled', false); }, 500);*/
$("#startTime").html(moment(event.start).format('MMM Do YYYY, h:mm A'));
$("#endTime").html(moment(event.end).format('MMM Do YYYY,h:mm A'));
$("#eventContent").dialog({modal: true, title: event.title, width: 100});
$('.delete-event').bind('click', function (e) {
$('#calendar').fullCalendar('removeEvents', event._id);
deleteEvent(event.id);
$("#eventContent").hide();
});
$('.discard-delete').bind('click', function () {
$("#eventContent").hide();
});
});
},
});
});
No duplicate event is created in the database. What is happening a the event HTML is rendering twice after refresh. Specifically fc-time-grid-event under the event container class is rendering twice after refresh.
The cause of the duplication is here, in your events function:
$('#calendar').fullCalendar('addEventSource', events);
callback(events);
You are adding the event objects as an event source, AND sending them back to the calendar as a list of events, in the documented way. So while the events may not be duplicated in your database, your code is sending two sets of identical event data to the calendar, and consequently they are displayed twice.
You can simply remove this line:
$('#calendar').fullCalendar('addEventSource', events);
as it is totally unnecessary in this context.

fullcalendar - multiple sources to turn off and on

I've a calendar that I want to list various types of event on and enable a checkbox filter to show/hide those kind of events.
Is there a way to say on this action, ONLY load from 1 data-source AND remember that URL on month next/prev links?
I've started using eventSources, but it loads them all, rather than the one(s) I want.. Here's what I have.
var fcSources = {
all: {
url: tournament_url + '/getCalendar/?typefilter=[1,2]'
},
type1: {
url: tournament_url + '/getCalendar/?typefilter=[1]'
},
type2: {
url: tournament_url + '/getCalendar/?typefilter=[2]'
}
};
These URLS all provide a json string of events, based on the types prrovided.
Here's my calendar:
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek'
},
firstDay: 1, // Monday = 1
defaultDate: new Date(), // Now
editable: true,
eventSources: [ fcSources.all ],
events: fcSources.all,
nextDayThreshold: '00:00:00',
... etc etc
Above my calendar I have this:
input type="checkbox" name="event_filter[]" value="type1" /> Type 1
input type="checkbox" name="event_filter[]" value="type2" /> Type 2
And finally , two Jquery fucntions.. one to get all the filters:
function getFilters(getName) {
var filters = [];
var checked = [];
$("input[name='"+getName+"[]']").each(function () {
filters.push( $(this).val() );
});
$("input[name='"+getName+"[]']:checked").each(function () {
checked.push( $(this).val() );
});
return [filters, checked];
}
and the last to load them:
$(".event_filter").on('click', function() {
var doFilters = getFilters('event_filter');
$('#calendar').fullCalendar( 'removeEvents' );
if (doFilters[0] === doFilters[1]) {
$('#calendar').fullCalendar( 'addEventSource', fcSources.all );
} else {
$.each(doFilters[1], function(myFilter, myVal) {
console.log(myVal);
$('#calendar').fullCalendar( 'addEventSource', fcSources.myVal );
});
}
// $('#calendar').fullCalendar( 'refetchEvents' );
});
Since the sources are all the same place and just different data on the URL, this approach could meet your needs. In the demo it just alerts the URL that is being tried but doesn't actually supply any data...
https://jsfiddle.net/gzbrc2h6/1/
var tournament_url = 'https://www.example.com/'
$('#calendar').fullCalendar({
events: {
url: tournament_url + '/getCalendar/',
data: function() {
var vals = [];
// Are the [ and ] needed in the url? If not, remove them here
// This could (should!) also be set to all input[name='event_filter[]'] val's instead of hard-coded...
var filterVal = '[1,2]';
$('input[name="event_filter[]"]:checked').each(function() {
vals.push($(this).val());
});
if (vals.length) {
filterVal = '[' + vals.join(',') + ']' // Are the [ and ] needed in the url? If not, remove here too
}
return {
typefilter: filterVal
};
},
beforeSend: function(jqXHR, settings) {
alert(unescape(settings.url));
}
}
});
// when they change the checkboxes, refresh calendar
$('input[name="event_filter[]"]').on('change', function() {
$('#calendar').fullCalendar('refetchEvents');
});
Try this!
$('#calendar').fullCalendar({
events: function( start, end, timezone, callback ) {
var checked = [];
$("input[name='event_filter[]']:checked").each(function () {
checked.push( $(this).val() );
});
var tournament_url = 'https://www.example.com';
$.ajax({
url: tournament_url + '/getCalendar/',
data: {typefilter: '['+checked.join(',')+']'},
success: function(events) {
callback(events);
}
});
}
});
$('input[name="event_filter[]"]').on('change', function() {
$('#calendar').fullCalendar('refetchEvents');
});
This works for me.

bootstrap3 pretty-fullcalendar meteor not reactive in blaze

I'm using a bootstrap3 pretty-fullcalendar in a project and pre blaze, when I changed some properties of an event (such as color) it was immediately reflected in the display on the calendar. Now, when I change the attribute, I have to reload the calendar manually to have the change show up.
I'm instantiating the calendar in the template render function as
Template.packLayout.rendered = function(){
$('#calendar').fullCalendar({
//dayClick:function( date, allDay, jsEvent, view ) {
// Requests.insert({title:'Request',start:date,end:date,color:'red',className:'todo'});
// Session.set('lastMod',new Date());
//},
eventClick:function(reqEvent,jsEvent,view){
Session.set('editingReqEvent',reqEvent.id);
Session.set('showEditEvent',true);
},
eventDrop:function(reqEvent){
Requests.update(reqEvent.id, {$set: {start:reqEvent.start,end:reqEvent.end}});
Session.set('lastMod',new Date());
},
events: function(start, end, callback) {
var events = [];
reqEvents = Requests.find();
reqEvents.forEach(function(evt){
event = {id:evt._id,title:evt.title,start:evt.start,end:evt.end,color:evt.color};
events.push(event);
})
callback(events);
},
editable:true,
weekMode: 'liquid'
});
}
Has something changed that would make this happen?
Here is how i managed to get it working:
1) keep your calendar code as per "rendered"
Template.calendar.rendered = function () {
console.log('Calendar - running redered');
Session.set('calendarTemplateRendered', true);
var entries = Calendar.find().fetch(),
$calendar = $('#calendar');
$calendar.html('').fullCalendar({
header: {
left: '',
center: '',
right: ''
},
contentHeight: 1100,
defaultDate: '2014-01-12',
defaultView: 'agendaWeek',
editable: true,
selectable: true,
selectHelper: true,
select: function (start, end) {
var title = prompt('Event Title:');
var eventData;
if (title) {
eventData = {
title: title,
start: start,
end: end
};
$('#calendar').fullCalendar('renderEvent', eventData, true); // stick? = true
}
$('#calendar').fullCalendar('unselect');
},
events: entries
});
Add a autorun:
Deps.autorun(function () {
if (Session.equals('calendarTemplateRendered', false) ||
!calendarSubs.ready() ||
typeof Calendar === 'undefined') {
console.log('exiting because there is no objects to process');
return;
}
console.log('trying to autorun');
var entries = Calendar.find().fetch(),
$calendar = $('#calendar');
$calendar.fullCalendar('removeEvents');
$calendar.fullCalendar('addEventSource', entries);
$calendar.fullCalendar('rerenderEvents');
}
Blaze will do the rest for you - (redraw the UI properly). Now you can just modify your Calendar subscription as you like and it will work perfectly.

Display only allDay events in a month view full calendar

How to display only allDay = true events in full calendar month view , and remaining non all Day events as usal in other views
You can do this by checking for view.name in a callback like eventRender. Take a look at this fiddle: http://jsfiddle.net/100thGear/vyKSZ/
Hope this helps!
$('#external-events div.external-event').each(function() {
// store data so the calendar knows to render an event upon drop
$(this).data('event', {
title: $.trim($(this).text()), // use the element's text as the event title
stick: true // maintain when user navigates (see docs on the renderEvent method)
});
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 1111999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
/* initialize the calendar
-----------------------------------------------------------------*/
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek'
},
editable: true,
droppable: true, // this allows things to be dropped onto the calendar
drop: function() {
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
$(this).remove();
}
},
eventDrop: function(event, delta, revertFunc) {
alert( event.id );
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath}/task/periodic-task-update",
data : {
id : event.id ,
date :event.start.format()
},
success: function(data) {
if(data=='Task Period Succesfully Changed'){
toastr.success("Task Period Succesfully Changed.");
}else{
toastr.success("Something Wrong");
revertFunc();
}
},
error: function(data,textStatus,xhr) {
toastr.success("Something Wrong");
revertFunc();
}
});
},
events: [
<c:forEach var='periodicTask' items='${periodicTaskTemplates}'>
<c:forEach varStatus="i" begin = "1" end = "12">
{ id: '${periodicTask.id}', title: '${periodicTask.task}', start: new Date(y, '${i.index}', '${periodicTask.startDate}'), end: new Date(y, '${i.index}', '${periodicTask.lastDate}') ,type:'${periodicTask.description}',location:'${periodicTask.location.name}'},
</c:forEach>
</c:forEach>`
],
});

Resources