Order Events in Fullcalendar by Start date and End Date - fullcalendar

How can I order events in fullCalendar first by start date?
Example:
An event which starts first will show on top and then one which starts later will be later
If two events have same the start date then, order them by end date
i.e
an event which ends earlier will be shown first, followed by an event which ends later.
Calendar Display
Events Order
var args = jQuery.parseJSON(emCalendarArgs);
var Jobj = args.events;
// Setup FullCalendar
(function() {
//var language = jQuery('#pg_lang').val();
//alert(language+ 'dsfsd');
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
var language = langg;
var mn_text, week_text, day_text, list_text;
//alert(mn_text);
var args = jQuery.parseJSON(emCalendarArgs);
var Jobj = args.events;
console.log(Jobj);
jQuery('#events-full-calendar').fullCalendar({
allDaySlot: false,
editable: true,
lang: 'he',
handleWindowResize: true,
eventOrder: 'start,end',
header: {
left: 'today prev,next',
center: 'title',
right: 'month,basicWeek,basicDay'
},
buttonText: {
month: mn_text,
week: week_text,
day: day_text
},
eventLimit: {
'month': 3, // adjust to 4 only for months
'default': false // display all events for other views
},
axisFormat: 'HH:mm',
timeFormat: {
agenda: 'H:mm{ - h:mm}'
},
slotEventOverlap: false,
events: Jobj,
timeFormat: 'H:mm',
});
}());

I found a Solution to it. For any one else looking for the solution to this, I changed a function in fullcalendar.js:
compareSegs: function(seg1, seg2) { return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1) compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs); }
to :
compareSegs: function(seg1, seg2) {
if(this.view.name=="basicWeek" || this.view.name=="month" || this.view.name=="basicDay"){ // ordering events by color in ListView
return seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs);
}
else{
return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first
seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first
seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs);
}
}
and used below code in fullcalendar function
eventOrder: 'start, end'
in my fullcalendar call

Related

Full Calendar v3 extending display beyond end of calendar year in List View

Good morning!
I have a list view set up in full calendar and have noticed that it will not display events beyond the end of the year. With it being now mid-December, this is a bit of a problem for me. We have several event that should be displaying in this list. When I change the view to month I have to click the next month button to get next years events, but at least with that I do sucessfully see the events in question.
Is there a way for my list view calendars to roll-over and include next year entries as I approach the end of the current year?
Here is an excerpt of what I have that effects the display of my calendar:
{url:'https://calendar.mydomain.com/services/id/38djsuw3hr-au8reh39dq/organization/1/department/13/',event_properties:{color:'#6a9b49'}},
]
function data_req (url, callback) {
req = new XMLHttpRequest()
req.addEventListener('load', callback)
req.open('GET', url)
req.send()
}
function add_recur_events() {
if (sources_to_load_cnt < 1) {
$('#calendar').fullCalendar('addEventSource', expand_recur_events)
} else {
setTimeout(add_recur_events, 30)
}
}
function load_ics(ics){
data_req(ics.url, function(){
$('#calendar').fullCalendar('addEventSource', fc_events(this.response, ics.event_properties))
sources_to_load_cnt -= 1
})
}
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: '',
center: '',
right: '' //view options on top-right (supported by v2.9.1 currently)
},
viewDisplay: function(view) {
parent.setIframeHeight(iframeId) ;
},
eventClick: function(event) {
// opens events in a new window or tab
window.open(event.url,);
return false;
},
// eventDataTransform: function(rawEventData){
// return {title: rawEventData.Title
// };
// },
defaultView: $(window).width() < 765 ? 'listYear':'listYear', //carryover code from full sized calendar
nowIndicator: false, //show a marker for current time
eventLimit: 4, // allow "more" link when too many events
fixedWeekCount: false, // have blank rows on a 6 or 7 row month
listDayFormat: 'MMMM Do',
listDayAltFormat: false,
allDayDefault: false,
noEventsMessage: "No Currently Scheduled Events"
})
sources_to_load_cnt = ics_sources.length
for (ics of ics_sources) {
load_ics(ics)
}
add_recur_events()
})
All I see is my "NoEventsMessage" text when in list view. If I create a test event the occurs prior to the end of the year it shows up in list view.
Any ideas on spanning calendar end?
thanks
[Edit: I should say that the link at the top is a JSON feed, so I am not using a prefilled list of events from within my script or from within an external file]
Here is how I solved it.
I created a custom view entry for the specific default view called "list" and gave it a one year duration:
views: {
list: {
duration: { days:365 }
}
},
I reset my default view from the dynamic version I carried over from my full-sized calendar (since I am using this in a column anyway and the window width call is not needed):
From:
defaultView: $(window).width() < 765 ? 'listYear':'listYear',
To:
defaultView: 'list',
After doing those things my January entries for next year began to display in list view.
Here is what my display calls look like (If someone wants to edit this to make it look prettier and more efficient, I don't mind :).
ics_sources = [
{url:'https://calendar.mydomain.com/services/id/38djsuw3hr-au8reh39dq/organization/1/department/13/',event_properties:{color:'#6a9b49'}},
]
function data_req (url, callback) {
req = new XMLHttpRequest()
req.addEventListener('load', callback)
req.open('GET', url)
req.send()
}
function add_recur_events() {
if (sources_to_load_cnt < 1) {
$('#calendar').fullCalendar('addEventSource', expand_recur_events)
} else {
setTimeout(add_recur_events, 30)
}
}
function load_ics(ics){
data_req(ics.url, function(){
$('#calendar').fullCalendar('addEventSource', fc_events(this.response, ics.event_properties))
sources_to_load_cnt -= 1
})
}
$(document).ready(function() {
$('#calendar').fullCalendar({
header: false,
viewDisplay: function(view) {
parent.setIframeHeight(iframeId) ;
},
eventClick: function(event) {
// opens events in a new window or tab
window.open(event.url,);
return false;
},
defaultView: 'list',
nowIndicator: false, //show a marker for current time
eventLimit: 4, // allow "more" link when too many events
fixedWeekCount: false, // have blank rows on a 6 or 7 row month
listDayFormat: 'MMMM Do',
listDayAltFormat: false,
noEventsMessage: "No Currently Scheduled Events",
views: {
list: {
duration: { days: 365 },
}
}
})
sources_to_load_cnt = ics_sources.length
for (ics of ics_sources) {
load_ics(ics)
}
add_recur_events()
})
Thanks.
[edit: removed extraneous backticks from answer.]

FullCalendar - Get Background event on dayClick

I'm currently trying to get an event (type of background) when the DayClick is trigger.
I can't use the EventClick trigger because of the background type (I don't know why but nothing happen in my case, something wrong from FullCalendar ?).
This is my code for the init :
$('#calendarRoomUnavailable').fullCalendar({
height: 'auto',
header: {
left : '',
center: 'title',
right: ''
},
defaultView: 'year',
defaultDate: getDateFilterRoomAvailable(),
lang: 'fr',
firstDay: 1,
columnFormat: 'ddd D/M',
selectable : false,
weekends: false,
navLinks : false,
events: basePath + '/agenda/datalist/room_available',
viewRender: function (view, element) {
},
eventRender: function(event,element){
if(event.rendering === "background"){
element.data(event); //store the event data inside the element
}
},
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
},
editable:false,
});
Quick look
What I want:
When I click on a day, I want the get the event(background) related to the day (I've got only one event per day in my calendar).
Currently I'm working with the eventRender + dayClick :
eventRender: function(event,element){
if(event.rendering === "background"){
element.data(event); //store the event data inside the element
}
},
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
[...]
}
With the console.log JSEvent on the DayClick, I know it get me the wrong <td> :
Img
Because, when I try to get the target <td> with the class fc-bgevent, nothing happens :
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
if (jsEvent.target.classList.contains('fc-bgevent')) {
console.log($(jsEvent.target).data());
}
If I try to go to the HTML element target getted by the jsEvent, it shows me the wrong <td> and I can't do anything with that ...
HTML Debug
Does someone know how to bypass that ?
Thanks !
Code to get one event from a date :
function getEventFromDate(date) {
var allEvents = [];
allEvents = $('#calendarRoomUnavailable').fullCalendar('clientEvents');
var event = $.grep(allEvents, function (v) {
return +v.start === +date;
});
if (event.length > 0) {
return event[0];
} else {
return null;
}
}
After the #ADyson comments, my final function look like this :
function getEventFromDate(date) {
var eventToReturn = null;
$('#calendarRoomUnavailable').fullCalendar('clientEvents', function(event) {
var event_start = formatDateYmd(new Date(date),'-');
var date_formated = formatDateYmd(new Date(event.start),'-');
if(event_start === date_formated) {
eventToReturn = event;
}
});
return eventToReturn;
}
with a small function to get a formated date without library like Moment.js or Date.js:
function formatDateYmd(value,$delimiter)
{
var year = value.getFullYear();
var month = (value.getMonth()+1) < 10 ? '0'+(value.getMonth()+1) : (value.getMonth()+1);
var day = value.getDate() < 10 ? '0'+value.getDate() : value.getDate();
return year + $delimiter +
month + $delimiter +
day;
}
I hope to find something more performant, but this one divide the execution time by two.
Keep an eye on it
Thanks again.

Disable event creation on Weekends

I am trying to use Fullcalendar for one of my leave application. I have select option enabled so that the user can select dates and apply leave on it. But I want to disable weekends from getting selected, ie it should give a alert when the user clicks on the weekends. Is it achivable?
My code
this.calendarOptions = {
height:450,
defaultDate: moment(new Date(),'YYYY-MM-DD'),
editable: false,
stick:true,
selectable:true,
eventLimit: false, // allow "more" link when too many events
events: this.eventList,
header: {
left: 'month basicWeek basicDay',
center: 'title',
right: 'today prev,next'
},
displayEventTime: false,
select: (start, end, allDay) => {
this.startDate=moment(start).format("YYYY-MM-DD");
this.endDate=moment(end).format("YYYY-MM-DD");
$('.first.modal').modal('show');
},
dayRender: (date, cell)=> {
//logic
},
selectOverlap:false,
};
You can do that on the select method. Just go from the startDate to the endDate and check if any of those days are weekends.
If so, display the alert / popup and return false.
select: (start, end, allDay) => {
var startDate = moment(start),
endDate = moment(end),
date = startDate.clone(),
isWeekend = false;
while (date.isBefore(endDate)) {
if (date.isoWeekday() == 6 || date.isoWeekday() == 7) {
isWeekend = true;
}
date.add(1, 'day');
}
if (isWeekend) {
alert('can\'t add event - weekend');
return false;
}
this.startDate= startDate.format("YYYY-MM-DD");
this.endDate= endDate.format("YYYY-MM-DD");
//$('.first.modal').modal('show');
},
See fiddle.

prevent an external event to be dropped on full calendar if earlier than today's date

I am using the fullcalendar jquery plugin to create a schedule of events. I want to prevent the user from dropping an external event on the calendar if it is earlier than current date.
This is my current code:
$('#edit_calendar').fullCalendar({
header:
{
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
titleFormat: { month: 'MMMM' },
defaultView: 'month',
droppable: true,
drop: function (date, jsEvent, ui, resourceId) {
//compare today's date with drop date - if in the past, don't allow
var today = moment().startOf('day');
var dropDate = moment(date).startOf('day');
if (dropDate < today)
{
//The alert is shown
alert("An event in the past cannot be added, updated, or deleted.");
return false;
}
else
{
var memberName = $(this).data('event').title;
var memberID = $(this).attr('id').toString();
//Create Event - add to array
var newEvent = new Object();
newEvent = {
title: memberName,
id: memberID,
start: date.format(),
end: date.format(),
objectID: 0
};
eventsAdded.push(newEvent);
}
},
...rest of code
If the event is dropped before the current day display the alert and do not create the event. If shown after the current day, create the event.
In the code above, the alert is shown, but the event is still created. If the event is dropped after the current day, the event is created.
I thought by adding return false after the alert is displayed it will prevent the event from being created. However, the alert is shown AND the event is created.
Do I have to remove the event or is there a way to prevent the event from being created?
I was able to restrict events when they are added or changed using the selectConstraint and eventConstraint respectively. However, I would like to add an alert when the user tries to update or add an event outside the start and end dates so they know why it is not working.
This is what I have:
$('#edit_calendar').fullCalendar({
header:
{
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
titleFormat: { month: 'MMMM' },
defaultView: 'month',
droppable: true,
drop: function (date, jsEvent, ui, resourceId) {
var memberName = $(this).data('event').title;
var memberID = $(this).attr('id').toString();
//Create Event - add to array
var newEvent = new Object();
newEvent = {
title: memberName,
id: memberID,
start: date.format(),
end: date.format(),
objectID: 0
};
eventsAdded.push(newEvent);
},
editable: true,
//The following constraints prevents the user from adding/updating/deleting events that are before the current date
//The end date is required. So, you can't add events over a year away from the current date
eventConstraint: {
start: moment().startOf('day'),
end: moment(moment().startOf('day'), 'MM-DD-YYY').add('days', 365)
},
selectConstraint: {
start: moment().startOf('day'),
end: moment(moment().startOf('day'), 'MM-DD-YYY').add('days', 365)
},
...rest of code...
Is there any way I can add an alert when the user tries to add or update an event ou
From the documentation:
eventDrop does not get called when an external event lands on the calendar. eventReceive is called instead
Having said that, in order to prevent the drop you need to go more back in the chain. You need to use "dropAccept". You can read about it in the documentation.
You can use 'removeEvents' to remove added event.
https://fullcalendar.io/docs1/event_data/removeEvents/
drop: function(date, jsEvent, ui, resourceId) {
var add = true;
... // Here decide whether to add or not
if(add){
;
}
else{
//use 'removeEvents' to remove added event
}
}

fullCalendar only display events on agendaView

I'm trying to get the fullCalendar JS application to display events only when on the agendaView view, not on the month view.
This is my current code. The problem is the events function is only called once, on the initial page load. According to documentation (and another site I have with fullCalendar) this function should call every time I change view, or date range. It does not.
$('#calendar').fullCalendar({
events: function ( start, end, timezone, callback ) {
var view = $('#calendar').fullCalendar('getView');
console.log(view.name);
if(view.name == 'agendaDay') {
$.ajax({
type: 'POST',
url: 'index.php?events=true',
data: {
start: start,
end: end
},
async: true,
success: function ( data ) {
callback(data);
}
});
}
},
dayClick: function ( date, jsEvent, view ) {
if(view.name == 'month' && jsEvent.currentTarget.className.indexOf('date-disabled') <= -1) {
$('#calendar').fullCalendar('changeView', 'agendaDay');
$('#calendar').fullCalendar('gotoDate', date);
} else if(view.name == 'agendaDay') {
var check = moment(date).format('YYYY-MM-DD');
var today = moment(new Date()).format('YYYY-MM-DD');
if(check > today) {
alert(date);
}
}
},
header: {
left: 'title',
center: '',
right: 'today month,agendaDay prev,next'
},
dayRender: function ( date, cell ) {
var check = moment(date).format('YYYY-MM-DD');
var today = moment(new Date()).format('YYYY-MM-DD');
if(check <= today) cell[0].className += ' date-disabled';
}
});
I know this for fact as the console.log only logs once, the word month. So it's only called when I refresh the page, first load it. Not when changing views which it should.
I was missing the lazyFetching option. This must be a new option in v2 as I was not expecting it.
http://arshaw.com/fullcalendar/docs/event_data/lazyFetching/
My code was correct. I simply needed to tell fullCalendar to get the events at EVERY change of the view and anything else that happened event wise.
lazyFetching: false,
This now works with my code.

Resources