I am trying to use the Fullcalendar where I need to show multiple resources with respective multiple events. The same source may have more events, including the situation of overbooking.
In the front-end I use Ajax to retrieve the datas for the resources and the events separately.
The following is my code; but it does not work. It fetches the resources and the events, shows the resources but unable to show the respective events.
How can I do it? Thanks a lot.
var calendar = new FullCalendar.Calendar(calendarEl, {
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
plugins: [ 'interaction', 'resourceTimeline' ],
timeZone: 'Europe/Rome',
defaultDate: today,
locale: 'it',
views: {
timelineFourDays: {
type: 'timeline'
//,duration: { months: 4 }
}
},
defaultView: 'resourceTimelineMonth',
lang: 'it',
aspectRatio: 1.5,
header: {
left: 'prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth,resourceTimelineYear'
},
footer: {
left: 'prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth,resourceTimelineYear'
},
resourceAreaWidth: '30%',
resourceLabelText: 'IMPIANTI',
resourceGroupField: 'nome_tipologia',
resourceOrder: 'id',
resourcesInitiallyExpanded: true,
resourceText: 'title',
refetchResourcesOnNavigate: true,
resourceColumns: [
{
labelText: 'IMPIANTO',
field: 'id_impianto',
width: '5%'
},
{
labelText: 'IDENTIFICATIVO',
field: 'impianto_codifica',
width: '15%'
}
,
{
labelText: 'COMUNE',
field: 'nome_comune',
width: '15%'
},
{
labelText: 'ARTICOLO',
field: 'nome_articolo',
width: '15%'
}
],
resources:{
url: '/listallimpiantos',
method: 'get',
_token: CSRF_TOKEN
},
resourceRender: function(renderInfo) {
renderInfo.el.style.backgroundColor = 'green';
renderInfo.el.style.color = '#ffffff';
},
eventSources:{
url: '/listimpiantosperofferta',
method: 'get',
_token: CSRF_TOKEN,
resourceIds:'title'
},
eventRender: function(event, element) {
$(element).tooltip({title: event.title});
if (event.statovendita == 'VENDUTO') {
element.css("background-color", '#378006');
}
if (event.statovendita == 'OPZIONATO') {
element.css("background-color", '#FFA500');
}
},
eventColor: '#378006',
eventBackgroundColor: event.color,
editable: true,
eventStartEditable: true,
eventResizableFromStart: true,
eventDurationEditable: true,
eventResize: function(info) {
alert("Per il cliente " + info.event.title + " dal " + info.event.start.toISOString() + " al " + info.event.end.toISOString());
if (!confirm("Confermi?")) {
info.revert();
} else {
alert('Aggiornamento sul db!');
}
},
selectable: true,
selectAllow: function(select) {
return moment().diff(select.start) <= 0
},
});
}
});
calendar.render();
});
Your eventSources definition is incorrect.
The documentation for eventSources it states that you must provide an array for this option. However, you have provided an object instead.
Since you are only providing one event source, you can either
a) change eventSources to events (because that option will accept a single object), i.e.
events: {
url: '/listimpiantosperofferta',
method: 'get',
_token: CSRF_TOKEN,
resourceIds:'title'
},
or
b) give eventSources an array containing a single item:
eventSources: [{
url: '/listimpiantosperofferta',
method: 'get',
_token: CSRF_TOKEN,
resourceIds:'title'
}],
The other issue you might have is a similar data-type error: The resourceIds option of the event source object expects an array (again you should check the documentation carefully), not a string.
So again to fix that you can either a) use the singular resourceId option instead:
resourceId: 'title'
or continue to use resourceIds but give it an array containing a single item:
resourceIds: ["title"]
Always remember to study the documentation closely and ensure you're matching the relevant syntax, data types, option names etc. Since JavaScript doesn't have compile-time type checking it's easy to overlook this kind of issue, and it will also often fail silently. That's why you have to pay close attention to examples and specifications beforehand.
Related
I use one source from PHP and it's work thine ! (i'm on fullcalendar v3)
> $('#calendar').fullCalendar({
events: {
url: myevents.php,
type: 'GET',
data: {
param: parametreFilter
},
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
lazyFetching: false,
editable: true,
droppable: true, ...
Now i would like to add events from another source. A gouvernemental API that display holidays. So i tried a lot of things and nothing works:
$('#calendar').fullCalendar({
eventSources:[
// your event source
{
url: 'https://calendrier.api.gouv.fr/jours-feries/metropole.json',
type: 'GET',
},
{
url: myevents.php,
type: 'GET',
data: {
param: parametreFilter
}
},
],
eventDataTransform:function(eventData){
console.log("YEP: " + JSON.stringify(eventData)); /* I tried this but the source from API never come in that function */
return eventData;
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
lazyFetching: false,
editable: true,
droppable: true,
dragScroll: true,
defaultView: 'agendaWeek',...
I saw this too: https://codepen.io/acerix/pen/EQePxq?editors=0010 But i can't apply it to my example.
I forgot something: I wrote a function to format the events from API, but i think that when i use it, the fullcalendar render is already finish before i get the events from API and reformat them. So its never displayed.
myholidays = []
function getHolidays(url) {
fetch(url)
.then(function(res) {
if (res.ok) {
return res.json().then(function(days) {
/*console.log(jours)*/
let i = 0
let holidays = []
for (const day in days) {
/*console.log(`${day}: ${days[day]}`);*/
holidays.push({ "title": days[day], "start":day+'T00:00:00', "allDay": true})
i++
}
myholidays.push.apply(feries,joursferies)
$('#calendar').fullCalendar( 'refetchEvents' );
})
}
else{
console.log("Error")
}
})
.catch(function(err) {
alert("Error: " + err)
});
}
Can you please help ?
The data at https://calendrier.api.gouv.fr/jours-feries/metropole.json is not an array containing objects in fullCalendar's event format so it will never display them.
You need to use the events-as-a-function option to download the data via your own AJAX request, and then process it into the correct format:
Your attempt above had one or two little mistakes in it, and also doesn't actually insert anything to the calendar, but it was a useful basis for a working solution:
eventSources: [
function (start, end, timezone, callback) {
fetch("https://calendrier.api.gouv.fr/jours-feries/metropole.json")
.then((response) => response.json())
.then(function (data) {
let holidays = [];
for (const day in data) {
holidays.push({
title: data[day],
start: day,
allDay: true
});
}
callback(holidays);
});
},
{
url: "myevents.php",
type: "GET",
data: {
param: parametreFilter
}
}
]
Demo: https://codepen.io/ADyson82/pen/eYvzqOp?editable=true&editors=001
I am using fullcalendar the non-es6 way, quite honestly because the bundled file was so large it was crashing stuff. Anyway, so I have loaded all the js files manually and all is well. Now I am trying to use Draggable. On the docs https://fullcalendar.io/docs/external-dragging it only shows you how to import Draggable from the interaction plugin. I have the interaction plugin up and running as I can drag events around on the calendar no problem, in fact I am editing bookings in Woo Bookings from them as they are dropped. I am now trying to drag resources from outside the calendar into the calendar and create bookings from them. I am getting Plugin file not loaded for draggable error in console, and of course Uncaught ReferenceError: Draggable is not defined
Here is my code
calendar = new FullCalendar.Calendar(calendarEl, {
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
plugins: [ 'resourceTimeline', 'interaction' ],
eventOverlap: false,
resourceGroupField: 'groupID',
resourceGroupText: 'groupText',
defaultView: 'resourceTimelineDay',
nowIndicator: true,
droppable: true,
defaultDate: currDate,
eventRender: function(info) {
$(info.el).find('.fc-content').attr("id", "event-" + info.event.id);
},
eventClick: function(info) {
info.jsEvent.preventDefault();
jQuery.colorbox({
href: wsccAppVars.standardajax,
data: {
action: 'fullcal_get_booking',
booking_id: info.event.id,
resource_id: info.event.resourceId
}
})
},
themeSystem: 'standard',
editable: true,
eventStartEditable: false,
eventDurationEditable: false,
resources: fcresources,
resourceColumns: [{
labelText: 'Lagoon',
field: 'lname'
}, {
labelText: 'Product',
field: 'pname'
}],
eventSources: [{
url: wsccAppVars.adminajax, // use the `url` property
color: 'yellow', // an option!
textColor: 'black' // an option!
}],
eventDrop: function(info) {
//console.log(info);
var data = {
booking_id: info.event.id,
resource_id: info.newResource.id,
protect: $("#calendar").data('cal-protect'),
action: 'wbsc_cal_booking_change'
}
//console.log(data);
$.post(wbscAppVars.standardajax, data, function(response) {
$("#calendar_messages").text(response.return_message)
if (!response.success) {
info.revert();
}
})
}
});
containerEl = document.getElementById('draggable_resources');
new Draggable(containerEl, {
itemSelector: '.draggable_resource'
});
calendar.render();```
I'm using FullCalendar v3 (latest) with a PHP backend.
I'm returning a JSON array from the backend broken up into 2 arrays. The first contains event details (a list of orders for the day, with the order# as the title), and the second contains a daily summary (with a sum of orders and work hours as the title). The array looks like this:
{"events":[{"id":709989,"item_no":"ABC123","title":709989,"color":"red","start":"2019-05-14","end":"2019-05-14","allDay":true,"total_hours":3,"remaining_hours":1.5},{"id":709990,"title":709990,"item_no":"ABC345","color":"red","start":"2019-05-15","end":"2019-05-15","allDay":true,"total_hours":5.7,"remaining_hours":3.2}],"summary":[{"id":338823,"title":"Orders: 14\rHours:28.33\rRemaining Hours:13.33","start":"2019-05-14","end":"2019-05-14","allDay":true},{"id":338824,"title":"Orders: 3\rHours:14.2\rRemaining Hours: 12.2","start":"2019-05-15","end":"2019-05-15","allDay":true}]}
There are other properties but these are the basics.
What I'm trying to do is change the array that's used as the event source depending upon which view is selected. I've tried custom event rendering, custom view rendering, multiple event sources (even though it's expensive from a data point-of-view, the # of records aren't so numerous that it greatly effects performance).
The custom view name is customMonth. When this view is selected, I just want to render the summary data (from the summary array). If any of the other views are selected (I'm using basicWeek, month and listWeek), render the events array.
let vname;
$("#calendar").fullCalendar({
defaultDate: new Date(),
defaultView: 'month',
eventRender: function(eventObj, $el, view) {
let n = view.name;
if(n=='customMonth')
{
vname = 'customMonth';
$el.popover({
title: eventObj.title,
content: eventObj.total_hours,
html: true,
trigger: 'hover',
placement: 'auto',
container: 'body'
});
} else {
vname = n;
$el.popover({
title: "Work Order " + eventObj.title,
content: '<strong>Item#</strong>: ' + eventObj.item_no + '<br />' + '<strong>Total Hours</strong>: ' + eventObj.total_hours + '<br />' + '<strong>Remaining Hours</strong>: ' + eventObj.remaining_hours,
html: true,
trigger: 'hover',
placement: 'auto',
container: 'body'
});
}
},
events: function(start, end, timezone, callback){
$.ajax({
url: '/myendpoint',
type: 'POST',
dataType: 'json',
data: {
action: 'get-calendar-summary',
cell: selected_cell
},
success: function(data) {
let events = [];
if(vname=='customMonth') {
obj = data.summary;
$(obj).each(function() {
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('dept_due_dt'),
end: $(this).attr('dept_due_dt'),
total_hours: $(this).attr('total_hours'),
remaining_hours: $(this).attr('remaining_hours'),
order_count: $(this).attr('day_order_count'),
has_late_order: $(this).attr('has_late_order'),
allDay: true,
earliest_date: $(this).attr('earliest_date')
});
});
} else {
obj = data.event_results;
$(obj).each(function() {
events.push({
id: $(this).attr('id'),
color: $(this).attr('color'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
earliest_date: $(this).attr('earliest_date'),
item_no: $(this).attr('item_no'),
total_hours: $(this).attr('total_hours'),
remaining_hours: $(this).attr('remaining_hours')
});
});
}
callback(events);
},
error: function(err) {
console.log(err);
}
});
},
views: {
customMonth: {
type: 'month',
buttonText: 'overview'
}
},
viewRender: function(view, el) {
let lastview;
if(view.name=='customMonth') {
if(lastview == 'customMonth') {
return false;
} else {
view.unrenderDates();
view.renderDates();
$("#calendar").fullCalendar('rerenderEvents');
}
lastview = 'customMonth';
} else {
if(lastview=='customMonth') {
view.unrenderDates();
view.renderDates();
$("#calendar").fullCalendar('rerenderEvents');
}
lastview = view.name;
}
},
header: {
left: 'prev,next',
center: 'title',
right: 'basicWeek,month,listWeek,customMonth'
},
themeSystem: 'bootstrap3',
timeZone: false,
weekends: false,
//tried with and without lazyFetching
lazyFetching: true
});
I'd appreciate any guidance. I've searched StackOverflow (this seems like the closest, but I followed exactly and it didn't work (switching out viewDisplay for viewRender)), Github, and all other sources I can think of.
Here a simplified example of what you are trying to achieve (I hope I well understand your problem) :
HTML :
<div id='calendar'></div>
Javascript :
$(document).ready(function() {
var ev1 = {"events":[{"id":709989,"item_no":"ABC123","title":'Event from source 1',"color":"red","start":"2019-05-14","end":"2019-05-14","allDay":true,"total_hours":3,"remaining_hours":1.5}]};
var ev2 = {"events":[{"id":709989,"item_no":"ABC123","title":'Event from source 2',"color":"blue","start":"2019-05-14","end":"2019-05-14","allDay":true,"total_hours":3,"remaining_hours":1.5}]};
$('#calendar').fullCalendar({
defaultDate: new Date(),
defaultView: 'month',
viewRender: function(view) {
if(view.type === 'basicWeek') {
$('#calendar').fullCalendar( 'removeEventSource', ev1 );
$('#calendar').fullCalendar( 'addEventSource', ev2 );
return;
}
},
header: {
left: 'prev,next',
center: 'title',
right: 'basicWeek,month,listWeek,customMonth'
},
});
$('#calendar').fullCalendar( 'addEventSource', ev1 );
});
And the codepen to try it.
It uses the callback function viewRender() to detect when a view change and addEventSource()/removeEventSource() to change the data. So when you change the view from month to week it will change the source events.
I have created a scheduler with following events and resources
var sampleEvents = [{ 'id': '1',
'resourceid': '27',
'start': '2018-09-19T07:00:00',
'stop': '2018-09-19T16:00:00',
'title': 'Message 1',
}];
var sampleResources = [{
facility_type: "Message Type",
id: '27',
title: "Message 1"
}];
$('#calendar').fullCalendar({
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
now: currenDate //Today's Date,
editable: false,
header: {
left: 'today prev,next',
center: 'title',
right: 'month,timelineDay,agendaWeek'
},
defaultView: 'month',
resourceGroupField: 'facility_type',
resourceColumns: [
{
labelText: 'Facility',
field: 'title',
width: 150,
},
],
resources: sampleEvents,
events: sampleResources,
dayClick: function(date, jsEvent, view) {
if(view.name == 'month' || view.name == 'basicWeek') {
$('#calendar').fullCalendar('changeView', 'timelineDay');
$('#calendar').fullCalendar('gotoDate', date);
}
},
});
}, function (error) {
});
The events are showing in month view, but they are not shown in day view. Can someone tell me where the problem is?
In JavaScript, variable and property names are case-sensitive. Therefore
'resourceid': '27'`
should be
'resourceId': '27'
as per the example in the documentation. The event isn't showing the timeline view because as far as fullCalendar is concerned you didn't tell it which resource to associate it with.
Assigned objects are improper. If you pass the correct objects. It will work fine
resources: sampleResources,
events: sampleEvents
You can refer below working jsfiddle link
http://jsfiddle.net/jso51pm6/3769/
resources: sampleEvents,
events: sampleResources,
You filled them wrong. Switch them. It will work.
resources: sampleResources,
events: sampleEvents,
FullCalendar v2.2.5, I want to use my JSON generating script to pull data only for the visible area of the calendar as mentioned in a few other questions.
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay',
defaultAllDay: true,
},
lazyFetching: false,
defaultDate: '2015-01-06',
editable: false,
eventLimit: 10,
weekMode: 'liquid',
dayPopoverFormat: 'DD/MM/YYYY',
//events: {
// url: 'instant-tools.cgi',
// type: 'POST',
// data: {
// events: 1,
// pending: 1,
// from: '2014-01-01',
// to: '2016-12-31',
// }
// },
viewRender: function(view, element) {
var events_slice = new Object();
events_slice.eventSources = [
{
url: 'instant-tools.cgi',
type: 'POST',
data: { events: 1, pending: 1, from: '2014-01-01', to: '2016-12-31' }
}
];
$('#calendar').fullCalendar('addEventSource', events_slice);
//$('#calendar').fullCalendar('renderEvents');
},
eventClick: function(calEvent, jsEvent, view) {
alert(calEvent.title + "n" + calEvent.start.format('DD/MM/YYYY') + " to " + calEvent.end.format('DD/MM/YYYY'));
},
});
});
The commented out events definition works (when I use it) but the viewRender one does not. Before you ask viewRender does get triggered. I get no errors in the console and no events displayed. My script is not called at all. I know I have the dates hardcoded right now but I will use view.intervalStart and view.intervalEnd once I verify I get a similar result. Having $('#calendar').fullCalendar('renderEvents'); in there makes no difference, also toggling lazyFetching does not make a difference. Not a JS coder so I hope I'm just being silly somewhere.
in the event property you need to call the function
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay',
defaultAllDay: true,
},
lazyFetching: false,
defaultDate: '$today',
editable: false,
eventLimit: 10,
weekMode: 'liquid',
dayPopoverFormat: 'DD/MM/YYYY',
events: function(start, end, timezone, callback) {
$.ajax({
url: 'instant-tools.cgi',
data: {
events: 1,
pending: 1,
from: '2014-01-01',
to: '2016-12-31',
},
success: function(doc) {
var obj = jQuery.parseJSON(doc);
var events = [];
$.each(obj, function(index, value) {
events.push({
id: value['id'],
//all data
});
//console.log(value)
});
callback(events);
},
error: function(e, x, y) {
console.log(e);
console.log(x);
console.log(y);
}
});
},
eventClick: function(calEvent, jsEvent, view) {
alert(calEvent.title + "n" + calEvent.start.format('DD/MM/YYYY') + " to " + calEvent.end.format('DD/MM/YYYY'));
},
});
});