jQuery UI Datepicker - color dates after the selected date - css

I'm using the jQuery UI datepicker to allow the user to select a date. I need to color 7 days after the selected date.
For example, if the user has selected 1.1.2015, the days 2.1.2015 to 8.1.2015 shall be colored upon click (on the 1.1.2015). I was following this guide but I am not able to make this work.
Basically what I'm doing is creating an array of future dates (based on the calculation of milliseconds from the selected date + 86400000 milliseconds for each day), and then trying to apply css class on this array. Please advise.
EDIT:
Maybe I should have mentioned, but this picker is inline so the changes must take place instantly.
EDIT2:
Here's an example via jsfiddle.
JS:
var arrayOfFollowingWeekDates = [];
var selectedStartingDate;
//date picker configuration
$('#datepicker').datepicker({
onSelect: function(dateText, inst){
selectedStartingDate = dateText;
var selectedDateAsObject = $(this).datepicker('getDate');
arrayOfFollowingWeekDates = calcFollowingtWeekDates(selectedDateAsObject);
if(selectedDateAsObject > new Date){
console.log(selectedStartingDate);
}else{
console.log("bad date.");
}
},
inline: true,
showOtherMonths: true,
beforeShowDay: function(day, date){
var day = day.getDay();
if (day == 5 || day == 6){
return [false, ""];
} else {
return [true, ""];
}
var highlight = arrayOfFollowingWeekDates[date];
if (highlight) {
return [true, "event", highlight];
} else {
return [true, '', ''];
}
}
});
//this creates an array of the desired week, based on date objects
function calcFollowingtWeekDates(selectedDateObj){
var followingWeek = [];
var tempArrayOfNextDates = [];
var selectedDateInMilliseconds = selectedDateObj.getTime();
console.log("selected date in milliseconds: "+selectedDateInMilliseconds);
tempArrayOfNextDates[0]=selectedDateInMilliseconds;
var day;
var prevDay=selectedDateInMilliseconds;
for(var i=0;i<7;i++){
tempArrayOfNextDates[i] = 86400000 + prevDay;
day = new Date(tempArrayOfNextDates[i]);
prevDay = tempArrayOfNextDates[i];
followingWeek[i]=day;
console.log("next day is : "+ day);
}
return followingWeek;
}
CSS:
.event a {
background-color: #42B373 !important;
background-image :none !important;
color: #ffffff !important;
}

Here is a working fiddle: http://jsfiddle.net/97L93a3h/2/
var selectedDay = new Date().getTime();
$('.datepicker').datepicker({
onSelect: function (date) {
selectedDay = $(this).datepicker('getDate').getTime();
},
beforeShowDay: function (date) {
var d = date.getTime();
if (d > selectedDay && d < selectedDay + 1 + 86400000 * 7) {
return [true, 'ui-state-highlight', ''];
} else {
return [true, ''];
}
}
});
Merge this method into your existing script.

Related

changeDate event return blank array when you click on same date in bootstrap datepicker(calendar view)?

So bootstrap datepicker return blank date if I click the same date again. However, how I know which date is again clicked by the user?
For example in below calendar, I clicked on 24th of April. Then changeDate event will return me below the array. Which is fine for me:
So anyone has any idea on how to know which date is again clicked by the user? Like how I can detect that the user is reclicked on the 24th?
My code:
Init of datepicker:
var DatePicker = {
hideOldDays: function(){ // hide days for previous month
var x = $('.datepicker .datepicker-days tr td.old');
if(x.length > 0){
x.css('visibility', 'hidden');
if(x.length === 7){
x.parent().hide();
}
}
},
hideNewDays: function(){ // hide days for next month
var x = $('.datepicker .datepicker-days tr td.new');
if(x.length > 0){
x.hide();
}
},
hideOtherMonthDays: function(){ // hide days not for current month
DatePicker.hideOldDays();
DatePicker.hideNewDays();
}
};
var arrows;
if (KTUtil.isRTL()) {
arrows = {
leftArrow: '<i class="la la-angle-right"></i>',
rightArrow: '<i class="la la-angle-left"></i>'
}
} else {
arrows = {
leftArrow: '<i class="la la-angle-left"></i>',
rightArrow: '<i class="la la-angle-right"></i>'
}
}
var date = new Date();
var active_dates_1 = ['13/3/2020','14/3/2020','15/3/2020','16/3/2020','17/3/2020','18/3/2020','20/3/2020','21/3/2020','22/3/2020','23/3/2020','24/3/2020','25/3/2020','26/3/2020','27/3/2020','28/3/2020','29/3/2020','30/3/2020','31/3/2020','2/4/2020','3/4/2020','5/4/2020','16/4/2020','17/4/2020',];
var active_dates_2 = ['1/4/2020','6/4/2020','7/4/2020','8/4/2020','9/4/2020','10/4/2020','11/4/2020','12/4/2020','15/4/2020','20/4/2020',];
var active_dates_3 = ['4/4/2020','13/4/2020','14/4/2020','24/4/2020','24/4/2020',];
date.setDate(date.getDate()+1);
$('#manage_datepicker_1').datepicker({
rtl: KTUtil.isRTL(),
todayHighlight: true,
templates: arrows,
startDate: date, //disable all old dates
setDate: date, //tomorrow's date allowed
multidate: true,
format: 'dd/mm/yyyy',
endDate: "25/04/2020",
beforeShowDay: function(date){
var d = date;
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1; //Months are zero based
var curr_year = d.getFullYear();
var formattedDate = curr_date + "/" + curr_month + "/" + curr_year
if ($.inArray(formattedDate, active_dates_1) != -1){
return {
classes: 'disabled bookedDates1'
};
}
if ($.inArray(formattedDate, active_dates_2) != -1){
return {
classes: 'disabled bookedDates2'
};
}
if ($.inArray(formattedDate, active_dates_3) != -1){
return {
classes: 'disabled bookedDates3'
};
}
return;
}
//maxDate: '28/12/2019'
});
$('#manage_datepicker_1').datepicker().on('show', function(event) {
DatePicker.hideOtherMonthDays(); //hide other months days from current month view.
}).on('changeDate', function(event) {
var storage = new Array();
console.log(event);
for (var i = 0; i < event.dates.length; i++) {
var formatted_date = moment(event.dates[i]).format('DD/MM/YYYY');
storage.push(formatted_date);
}
});
I think that having the clicked date is a reasonable requirement, that worth introducing a change into the source code of bootstrap-datepicker.
So, assuming you're using the minified version, there's a part that goes (ctrl+f for element.trigger):
this.element.trigger({
type: b,
date: e,
viewMode: this.viewMode,
dates: a.map(this.dates, this._utc_to_local),
...
})
Just add a clickedDate property:
this.element.trigger({
type: b,
date: e,
clickedDate: this.viewDate, // <-- added
viewMode: this.viewMode,
dates: a.map(this.dates, this._utc_to_local),
...
})
So that now, inside your changeDate handler, you could access event.dates as well as event.clickedDate.

FullCalendar RefetchEvents very slow

I call calendar.refetchEvents(); inside an autorun Block to ensure the reactivity of the Scheduler (i'm using resource view) , when tested with big datasets , although i make sure to subscript to only a portion of 2 weeks worth of events , it's extremly slow .
my events arent Json based i'm using meteor and i loop over the events inside the Events function of the calendar .
are there some good fullcalendar practices i'm missing ?
calendar = $('#calendar').fullCalendar({
now: new Date(),
editable: true, // enable draggable events
droppable: true, // this allows things to be dropped onto the calendar
aspectRatio: 1.8,
disableDragging: true,
displayEventTime: false,
selectable:true,
allDaySlot:true,
slotDuration:'24:00',
lazyFetching:true,
scrollTime: '00:00', // undo default 6am scrollTime
header: {
left: 'today prev,next',
center: 'title',
right: 'timelineThreeDays'
},
defaultView: 'timelineThreeDays',
views: {
timelineThreeDays: {
type: 'timeline',
duration: { days: 14 }
}
},
eventAfterAllRender: function(){
Session.set("loading",false);
},
resourceLabelText: 'Employees',
eventRender: function (event, element) {
var originalClass = element[0].className;
if (event.id && event.id.indexOf("temp")>-1){
element[0].className = originalClass + ' dragEvent';
}
else if (event.id && event.id.indexOf("oloc")>-1){
element[0].className = originalClass + ' oloc';
}
else{
element[0].className = originalClass + ' hasmenu';
}
$(element[0]).attr('shift-id', event._id);
element.find('.fc-title').html((event.title?event.title+"<br/>":"")+(event.locationName?event.locationName+"<br/>":"")+moment(event.start).format("HH:mm")+ " "+moment(event.end).format("HH:mm"));
element.bind('mousedown', function (e) {
if (e.which == 3) {
Session.set("selectedShift",event._id);
}
});
},eventAfterRender: function(event, element, view) {
},
resourceRender: function(resourceObj, labelTds, bodyTds) {
var originalClass = labelTds[0].className;
var uid=resourceObj.id;
var resource = Meteor.users.findOne({_id:uid});
if(resource){
var img = Images.findOne({_id: resource.picture});
var imgUrl = img ? img.url() : "/images/default-avatar.png";
var styleString = "<img class='img-profil small' src='"+imgUrl+"'>" + resource.profile.firstname + " " + resource.profile.lastname+" <small style='font-size:0.6em;color:#D24D57;'>"+resource.profile.registeredTelephony+"</small>";
labelTds.find('.fc-cell-text').html("");
labelTds.find('.fc-cell-text').prepend(styleString);
labelTds[0].className = originalClass + ' hasResourceMenu';
}else{
var imgUrl = "/images/default-avatar.png";
var styleString = "<img class='img-profil small' src='"+imgUrl+"'>" + "Unassigned" + " " +" <small style='font-size:0.6em;color:#D24D57;'>"+"</small>";
labelTds.find('.fc-cell-text').html("");
labelTds.find('.fc-cell-text').prepend(styleString);
}
},
resources: function(callback) {
var users = [];
var data = Meteor.users.find({
$or:[
{"profile.showInScheduler":{$exists:false}},
{"profile.showInScheduler":true}
],
assignedTo:{$in:[Session.get("locationId")]},
'locations._id':Session.get("locationId"),
"profile.companyId":Session.get("companyId")
});
var arr = data.map(function(c) {
var employeeType = c.userSettings.employeeType;
var type = EmployeeType.findOne({_id:employeeType});
var img = Images.findOne({_id: c.picture});
var imgUrl = img ? img.url() : "/images/default-avatar.png";
c.name = c.name || "";
var totalHoursAllLocation = 0;
var totalHoursCurrentLocation = 0;
return {
id: c._id,
title: "t"
};
});
arr.push({id:"temp"+Session.get("companyId")+Session.get("locationId"),title:"<div class='img-profil small' style='background: url(/images/default-avatar.png);'></div> UnAssigned"});
callback(arr);
},
events: function(start, end, timezone, callback) {
},
drop: function(date, jsEvent, ui, resourceId) {
// retrieve the dropped element's stored Event Object
var locationId=Session.get("locationId");
var originalEventObject = $(this).data('eventObject');
var copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = date;
//copiedEventObject.allDay = allDay;
shift = ShiftTypes.findOne({_id:copiedEventObject.id});
if(shift){
startDate = moment(date);
hour = shift.dayDuration.Start.split(":");
startDate.hours(hour[0]).minutes(hour[1]);
endDate = moment(date);
hour = shift.dayDuration.End.split(":");
endDate.hours(hour[0]).minutes(hour[1]);
if(moment(startDate).isAfter(endDate)){
endDate=endDate.add("1","days");
}
var data = {
shiftId:shift._id,
name:shift.name,
uid:resourceId,
locationId:Session.get("locationId"),
companyId:Session.get("companyId"),
day:date,start:startDate.utc().toDate(),
end:endDate.utc().toDate(),
type:"active"
};
if (SchedulesBeforeInsert(data,"dropActive")){
Schedules.insert(data,function (err,result) {});
}
}
},
eventResize: function( event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view ) {
endDate = moment.utc(new Date(event.start));
schedule = Schedules.findOne({_id:event.id});
var delta = dayDelta._days;
for(i=1;i<delta+1;i++){
Schedules.insert({start:moment.utc(event.start).add(i,"days").toDate(),end:moment.utc(schedule.end).add(i,"days").toDate(),uid:schedule.uid,locationId:Session.get("locationId"),companyId:schedule.companyId,name:schedule.name,shiftId:schedule.shiftId,attendanceCode:schedule.attendanceCode,type:schedule.type});
}
},
dayClick: function(date, jsEvent, view,res,res2) {
Session.set("selectedDay",moment(date).toDate());
Session.set("selectedRessource",res.id);
},
eventClick: function ( event, jsEvent, view ) {
toastr.success(moment(event.start).format('HH:mm') +" TO "+moment(event.endDate).format('HH:mm'))
},
eventReceive: function(event) { // called when a proper external event is dropped
console.log('eventReceive', event);
}
}).data().fullCalendar;
/********************* reactive calendar *****************/
this.autorun(function() {
console.log("autoRun")
Meteor.subscribe("schedules",Session.get("companyId"),moment($('#calendar').fullCalendar('getDate')).startOf('week').toDate(),moment($('#calendar').fullCalendar('getDate')).add(4,"weeks").endOf('week').toDate());
var events = [];
var usersInLocation = Meteor.users.find({$or:[{"profile.showInScheduler":{$exists:false}},{"profile.showInScheduler":true}],assignedTo:{$in:[Session.get("locationId")]},'locations._id':Session.get("locationId"),"profile.companyId":Session.get("companyId")}).fetch();
var userIds = _.pluck(usersInLocation,"_id");
userIds.push("temp"+Session.get("companyId")+Session.get("locationId"));
var data;
if(Session.get("displayAllLocations")===true){
reqEvents = Schedules.find({uid:{$in:userIds},companyId:Session.get("companyId"),type:{$in:["active","activeAttendance"]},start:{$gte:moment(Session.get("currentDate")).startOf('week').toDate()},end:{$lte:moment(Session.get("currentDate")).add(1,"week").endOf('week').toDate()}});
}else{
reqEvents = Schedules.find({uid:{$in:userIds},locationId:Session.get("locationId"),companyId:Session.get("companyId"),type:{$in:["active","activeAttendance"]},start:{$gte:moment(Session.get("currentDate")).startOf('week').toDate()},end:{$lte:moment(Session.get("currentDate")).add(1,"week").endOf('week').toDate()}});
}
reqEvents.forEach(function(evt){
var event = null;
color="";
if(evt.attendanceCode){
attendance =AttendanceCodes.findOne({_id:evt.attendanceCode});
color=attendance.color;
}
attendance = null;
color="";
id="";
locationName="";
if(evt.attendanceCode){
attendance =AttendanceCodes.findOne({_id:evt.attendanceCode})
if(attendance){
color=attendance.color;
}
}
else if(evt.employeeAttendanceCode){
attendance =AttendanceCodesPortal.findOne({_id:evt.employeeAttendanceCode})
if(attendance){
color=attendance.color;
}
}
id=evt._id;
if(evt.locationId!==Session.get("locationId")){
color="#EEEEEE";
id="oloc";
location =Locations.findOne({_id:evt.locationId});
if(location){
locationName=location.name;
}
}
if(evt.name != null){
event = {id:id,title:evt.name,start:evt.start,end:evt.end,color:color,resourceId:evt.uid,locationName:locationName};
}else{
event = {id:id,title:" ",start:evt.start,end:evt.end,color:color,resourceId:evt.uid,locationName:locationName};
}
events.push(event);
});
allUsersCursor =Meteor.users.find({
$or:[
{"profile.showInScheduler":{$exists:false}},
{"profile.showInScheduler":true}
],
assignedTo:{$in:[Session.get("locationId")]},
'locations._id':Session.get("locationId"),
"profile.companyId":Session.get("companyId")
}).fetch();
if(calendar){
calendar.removeEvents();
calendar.addEventSource(events);
calendar.refetchResources();
//SetUp the actions context menu
setUpContextMenu();
// Initialize the external events
$('#external-events div.external-event').each(function() {
var eventObject = {
title: $.trim($(this).text()), // use the element's text as the event title
id:$(this).attr("id")
};
// store the Event Object in the DOM element so we can get to it later
$(this).data('eventObject', eventObject);
// make the event draggable using jQuery UI
$(this).draggable({
helper: 'clone',
revert: 'invalid',
appendTo: 'body'// original position after the drag
});
});
}
});
I can see a number of non-Meteoric patterns in there that you should optimize out:
Your this.autorun will rerun anytime anything changes in your Schedules collection as well as for various user object changes (not just to the logged-in users but other users as well). Your autorun rebuilds your client-side data from scratch every time, including numerous joins. You could use a local collection to cache the joined data and then only add/change those documents when the underlying persisted document changes. This can be done with an observeChanges pattern. Or you could denormalize your data model a bit to avoid all those joins.
You're modifying the DOM by attaching events to a number of selectors using jQuery instead of using Meteor event handlers. This is also happening in your autorun which means you're attaching the same events to the same DOM objects repeatedly.
You use many Session variables and you use them repeatedly. These can be slow since they use browser local storage. You should .get() such data into a local variable once only and then refer to the local variable from then on.
Make sure that you only include fields in your Schedules publication that your code actually refers to on the client. The rest are overhead.

Add a new view to fullcalendar v 2.1.1

I want to add a new month view to fullcalendar where all the day are in column (like a timeline).
Is there a way to do that properly and remain compatible with the original plugin ?
Update
Note that fullcalendar now has another system for handling third party views and plugins.
How I do it now:
(function() {
'strict';
var FC = $.fullCalendar, // a reference to FullCalendar's root namespace
View = FC.View, // the class that all views must inherit from
ListView; // our subclass
ListView = View.extend({ // make a subclass of View
computeRange: function(date) {
var intervalDuration = moment.duration(this.opt('duration') || this.constructor.duration || {
days: 10
});
var intervalUnit = 'day';
var intervalStart = date.clone().startOf(intervalUnit);
var intervalEnd = intervalStart.clone().add(intervalDuration);
var start, end;
// normalize the range's time-ambiguity
intervalStart.stripTime();
intervalEnd.stripTime();
start = intervalStart.clone();
start = this.skipHiddenDays(start);
end = intervalEnd.clone();
end = this.skipHiddenDays(end, -1, true); // exclusively move backwards
return {
intervalDuration: intervalDuration,
intervalUnit: intervalUnit,
intervalStart: intervalStart,
intervalEnd: intervalEnd,
start: start,
end: end
};
},
initialize: function() {
// called once when the view is instantiated, when the user switches to the view.
// initialize member variables or do other setup tasks.
View.prototype.initialize.apply(this, arguments);
},
render: function() {
// responsible for displaying the skeleton of the view within the already-defined
// this.el, a jQuery element.
View.prototype.render.apply(this, arguments);
},
computeTitle: function() {
return moment().format(this.opt('titleFormat'));
},
setHeight: function(height, isAuto) {
// responsible for adjusting the pixel-height of the view. if isAuto is true, the
// view may be its natural height, and `height` becomes merely a suggestion.
this.el.height(height);
View.prototype.setHeight.apply(this, arguments);
},
renderEvents: function(events) {
// reponsible for rendering the given Event Objects
var noDebug = true;
noDebug || console.log(events);
var eventsCopy = events.slice().reverse(); //copy and reverse so we can modify while looping
var tbody = $('<tbody></tbody>');
this.scrollerEl = this.el.addClass('fc-scroller');
this.el.html('')
.append('<table style="border: 0; width:100%"></table>').children()
.append(tbody);
var periodEnd = this.end.clone(); //clone so as to not accidentally modify
noDebug || console.log('Period start: ' + this.start.format("YYYY MM DD HH:mm:ss Z") + ', and end: ' + this.end.format("YYYY MM DD HH:mm:ss Z"));
var currentDayStart = this.start.clone();
while (currentDayStart.isBefore(periodEnd)) {
var didAddDayHeader = false;
var currentDayEnd = currentDayStart.clone().add(1, 'days');
noDebug || console.log('=== this day start: ' + currentDayStart.format("YYYY MM DD HH:mm:ss Z") + ', and end: ' + currentDayEnd.format("YYYY MM DD HH:mm:ss Z"));
//Assume events were ordered descending originally (notice we reversed them)
for (var i = eventsCopy.length - 1; i >= 0; --i) {
var e = eventsCopy[i];
var eventStart = e.start.clone();
var eventEnd = this.calendar.getEventEnd(e);
if (!noDebug) {
console.log(e.title);
console.log('event index: ' + (events.length - i - 1) + ', and in copy: ' + i);
console.log('event start: ' + eventStart.format("YYYY MM DD HH:mm:ss Z"));
console.log('event end: ' + this.calendar.getEventEnd(e).format("YYYY MM DD HH:mm:ss Z"));
console.log('currentDayEnd: ' + currentDayEnd.format("YYYY MM DD HH:mm:ss Z"));
console.log(currentDayEnd.isAfter(eventStart));
}
if (currentDayStart.isAfter(eventEnd) || (currentDayStart.isSame(eventEnd) && !eventStart.isSame(eventEnd)) || periodEnd.isBefore(eventStart)) {
eventsCopy.splice(i, 1);
noDebug || console.log("--- Removed the above event");
} else if (currentDayEnd.isAfter(eventStart)) {
//We found an event to display
noDebug || console.log("+++ We added the above event");
if (!didAddDayHeader) {
tbody.append('\
<tr class="fc-header" date="">\
<th colspan="2">\
<span class="fc-header-day">' + currentDayStart.format('dddd') + '</span>\
<span class="fc-header-date">' + currentDayStart.format(this.opt('columnFormat')) + '</span>\
</th>\
</tr>');
didAddDayHeader = true;
}
/*
<td class="fc-event-handle">\
<span class="fc-event"></span>\
</td>\
*/
var segEl = $('\
<tr class="fc-row fc-event-container fc-content">\
<td class="fc-time">' + (e.allDay ? this.opt('allDayText') : e.start.format('H:mm') + '-' + e.end.format('H:mm')) + '</td>\
<td>\
<div class="fc-title">' + e.title + '</div>\
<div class="fc-description">' + e.location + '</div>\
</td>\
</tr>');
tbody.append(segEl);
//Tried to use fullcalendar code for this stuff but to no avail
(function(_this, myEvent, mySegEl) { //temp bug fix because 'e' seems to change
segEl.on('click', function(ev) {
return _this.trigger('eventClick', mySegEl, myEvent, ev);
});
})(this, e, segEl);
}
}
currentDayStart.add(1, 'days');
}
this.updateHeight();
View.prototype.renderEvents.apply(this, arguments);
},
destroyEvents: function() {
// responsible for undoing everything in renderEvents
View.prototype.destroyEvents.apply(this, arguments);
},
renderSelection: function(range) {
// accepts a {start,end} object made of Moments, and must render the selection
View.prototype.renderSelection.apply(this, arguments);
},
destroySelection: function() {
// responsible for undoing everything in renderSelection
View.prototype.destroySelection.apply(this, arguments);
}
});
FC.views.list = ListView; // register our class with the view system
})();
For older versions of fullcalendar
I made something like what you're talking about:
https://github.com/samedii/fullcalendar
Just set
basicListInterval: { 'days': 30 }
The view is called 'basicList'
Edit (more graphic solution):
src/basic/basicList.js
/* A view with a simple list
----------------------------------------------------------------------------------------------------------------------*/
fcViews.basicList = BasicListView; // register this view
function BasicListView(calendar) {
BasicView.call(this, calendar); // call the super-constructor
}
BasicListView.prototype = createObject(BasicView.prototype); // define the super-class
$.extend(BasicListView.prototype, {
name: 'basicList',
incrementDate: function(date, delta) {
var out = date.clone().stripTime().add(delta, 'days');
out = this.skipHiddenDays(out, delta < 0 ? -1 : 1);
return out;
},
render: function(date) {
this.intervalStart = date.clone().stripTime();
this.intervalEnd = this.intervalStart.clone().add(30, 'days');
this.start = this.skipHiddenDays(this.intervalStart);
this.end = this.skipHiddenDays(this.intervalEnd, -1, true);
this.title = this.calendar.formatRange(
this.start,
this.end.clone().subtract(1), // make inclusive by subtracting 1 ms
this.opt('titleFormat'),
' \u2014 ' // emphasized dash
);
BasicView.prototype.render.call(this, 30, 1, true); // call the super-method
}
});
I think you need to run npm install && bower install and then grunt dev to build.

jQuery date picker reset css classes

I have a collection of dates that I will use to instanciate my jquery datepicker widget. I have used beforeShowDay method to add a highlight css class to show on what days events are. The issue I encounter is that the css class is reset when I click on a date. Am I doing something wrong ?
Thanks
$("#datepicker").datepicker({
inline: true,
showOtherMonths: true,
showButtonPanel: false,
beforeShowDay: function(date) {
var result = [true, '', null];
var matching = $.grep(events, function(event) {
return event.date.valueOf() === date.valueOf();
});
if (matching.length) {
result = [true, 'highlight', null];
}
return result;
},
onSelect: function(dateText) {
}
});
Try this way, maybe you are not returning "true".
beforeShowDay: function(dates) {
for (i = 0, vetorLen = freedays.length; i < vetorLen; i++) {
if ($.inArray(dates,freedays) != -1) {
return [true, 'css-class-to-highlight', ''];
} else {
return [false, '', ''];
}
}
return [true];
},
hope this help you.

Can I prevent events with conflict time?

How can I prevent events with conflict time? Is there any variable to set up?
No, there is not a variable to set, but you can use something like clientEvents which retrieves events that fullcalendar has in memory. You can use the function below in the eventDrop. In the case below it uses a function to filter out whether the event will have have an overlap or not.
function checkOverlap(event) {
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event)
return false;
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (Math.round(estart)/1000 < Math.round(end)/1000 && Math.round(eend) > Math.round(start));
});
if (overlap.length){
//either move this event to available timeslot or remove it
}
}
you can add eventOverlap : false in the celendar config,
http://fullcalendar.io/docs/event_ui/eventOverlap/
Correct overlap checking.
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
/// deny overlap of event
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event) {
return false;
}
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (
( Math.round(start) > Math.round(estart) && Math.round(start) < Math.round(eend) )
||
( Math.round(end) > Math.round(estart) && Math.round(end) < Math.round(eend) )
||
( Math.round(start) < Math.round(estart) && Math.round(end) > Math.round(eend) )
);
});
if (overlap.length){
revertFunc();
return false;
}
}
Add custom property in the event object overlap:false for example your event object will be
`{
title:'Event',
start: '2017-01-04T16:30:00',
end: '2017-01-04T16:40:00',
overlap:false
}`
Now override selectOverlap function,
selectOverlap: function(event) {
if(event.ranges && event.ranges.length >0) {
return (event.ranges.filter(function(range){
return (event.start.isBefore(range.end) &&
event.end.isAfter(range.start));
}).length)>0;
}
else {
return !!event && event.overlap;
}
},
It will not let the another event to override the already placed event.
This does the trick. It also handles resizing overlapping events
var calendar = new Calendar(calendarEl, {
selectOverlap: false,
eventOverlap: false
}
});

Resources