My goal is to have 2 custom buttons to jump 1 week back and forth and another 2 buttons to jump 1 month back and forth. In contrary to the build-in prev and next buttons of FullCalendar, my buttons are supposed not to change with the duration of the view. I am stuck with the syntax here, calendar.incrementDate( moment.duration(-1, 'week') ) brings up Uncaught TypeError: e is null in browser. moment.js seems to work fine though. My code:
(...)
customButtons: {
prevWeek: {
text: '<',
click: function() {
calendar.changeView( 'resourceTimelineWeek' ), //works
calendar.incrementDate( moment.duration(-1, 'week') ), //error
alert('clicked the prevWeek button!');
}
}
},
headerToolbar: {
center: 'week,month',
right: 'today prevMonth,prevWeek,nextWeek,nextMonth'
},
slotLabelFormat: [
{ month: 'long', year: 'numeric' }, // top level of text
{ week: 'W' },
{ weekday: 'short', day: '2-digit' } // lower level of text
],
(...)
...and two more questions:
Is there a way not to use moment.js for this?
What is the best way to change the font size / add some custom CSS for a certain custom button (not for all buttons)?
With the hint from ADyson I've found the solution:
customButtons: {
prevWeek: {
text: '<',
click: function() {
calendar.changeView( 'resourceTimelineWeek' );
calendar.incrementDate( { days: -7 } );
}
},
Using fullcalendar library, I would like to display the start time for each empty cell on my calendar (empty cells are the one marked with a red cross or red dots in the below screenshot, I modified a bit the aspect of the calendar):
So my expected output is a calendar were timeslots become buttons, when you click you start the process of booking a 30 minutes appointment which would start at the written time (the green slot is an hover effect in the following screenshot):
I can't find any easy way to do it through after reading fullcalendar documentation : https://fullcalendar.io/docs
Subsidiary question, I can't find the way to change the style of the empty cell in the CSS. Can't manage to select the elements through my Chrome console.
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
columnHeaderHtml: function(date) {
if (date.getUTCDay() === 0) {
var date_day = "Lundi";
}
if (date.getUTCDay() === 1) {
var date_day = "Mardi";
}
if (date.getUTCDay() === 2) {
var date_day = "Mercredi";
}
if (date.getUTCDay() === 3) {
var date_day = "Jeudi";
}
if (date.getUTCDay() === 4) {
var date_day = "Vendredi";
}
if (date.getUTCDay() === 5) {
var date_day = "Samedi";
}
if (date.getUTCDay() === 6) {
var date_day = "Dimanche";
}
if(date.getMonth() === 0)
{
var date_month = "Jan";
}
if(date.getMonth() === 1)
{
var date_month = "Fev";
}
if(date.getMonth() === 2)
{
var date_month = "Mar";
}
if(date.getMonth() === 3)
{
var date_month = "Avr";
}
if(date.getMonth() === 4)
{
var date_month = "Mai";
}
if(date.getMonth() === 5)
{
var date_month = "Juin";
}
if(date.getMonth() === 6)
{
var date_month = "Juil";
}
if(date.getMonth() === 7)
{
var date_month = "Août";
}
if(date.getMonth() === 8)
{
var date_month = "Sept";
}
if(date.getMonth() === 9)
{
var date_month = "Oct";
}
if(date.getMonth() === 10)
{
var date_month = "Nov";
}
if(date.getMonth() === 11)
{
var date_month = "Dec";
}
var day_num = date.getDate();
return '<b>'+date_day+'</b><br><small>'+day_num+" "+date_month+"</small>";
},
plugins: [ 'interaction', 'dayGrid', 'list', 'googleCalendar','timeGrid' ],
selectable: true,
defaultView: 'timeGridFourDay',
views: {
timeGridFourDay: {
type: 'timeGrid',
duration: { days: 4 },
buttonText: '4 day'
}
},
slotLabelFormat:{
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
},
locale:'fr',
header: {
left: 'prev today',
right: 'next'
},
validRange: {
start: '2019-08-05',
end: '2019-09-05'
},
allDaySlot:false,
firstDay:1,
minTime:"08:00:00",
maxTime:"20:00:00",
displayEventTime: true, // don't show the time column in list view
// THIS KEY WON'T WORK IN PRODUCTION!!!
// To make your own Google API key, follow the directions here:
// http://fullcalendar.io/docs/google_calendar/
googleCalendarApiKey: 'AIzaSyAL9K2UqkCVfV0n81mDW0iEpOJSwcklfsY',
// US Holidays
events: 'fr.fr#holiday#group.v.calendar.google.com',
eventClick: function(arg) {
arg.jsEvent.preventDefault() // don't navigate in main tab
console.log(arg);
},
select: function(info) {
console.log(info)
},
loading: function(bool) {
},
eventSources: [
{
googleCalendarId: 'contact#vetorino.com',
className: "gcalEvent"
}],
displayEventEnd:false,
events:[
{ // this object will be "parsed" into an Event Object
start: '2019-08-05 12:30:00', // a property!
end: '2019-08-05 14:00:00', // a property! ** see important note below about 'e6d' **
overlap: true,
backgroundColor:"#F7F7F7",
textColor:"#979797",
classNames:"closed",
}],
contentHeight: "auto",
});
calendar.render();
});
So far as shown in my previous screenshot I just managed to have empty cells, the only cells where you find some information are cells containing events.
As discussed in the comments above, there is no single element in the fullCalendar HTML which represents a specific "cell" or "slot" in the timeGrid view. The grid you can see on screen is actually an illusion created by layering multiple tables on top of each other.
So to meet your requirement for a user to be able to select a 20-minute appointment in a free slot, I can see two main options. The first is what I would normally recommend, using the standard fullCalendar functionality. The second is more like what you are asking for, but I think it over-complicates things.
1) This option simply sets the calendar with a slot duration of 20 minutes, and then has code to stop the user from selecting a longer period of time (they cannot select a shorter period, due to the slotDuration setting. This means that they can click on any empty space once and it will know to create an event of the correct length in that location. The user is not allowed to select any slot where an event already exists. (P.S. I expect in reality you will need to collect more data before adding events, but for the demonstration it adds an event instantly.)
document.addEventListener("DOMContentLoaded", function() {
var Calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: ["timeGrid", "interaction"],
header: {
left: "prev,next today",
center: "title",
right: "timeGridFourDay"
},
defaultView: "timeGridFourDay",
views: {
timeGridFourDay: {
type: "timeGrid",
duration: { days: 4 },
buttonText: "4 day"
}
},
slotLabelFormat: {
hour: "numeric",
minute: "2-digit",
omitZeroMinute: true,
meridiem: "short"
},
allDaySlot: false,
firstDay: 1,
minTime: "08:00:00",
maxTime: "20:00:00",
contentHeight: "auto",
slotDuration: "00:20:00",
selectable: true,
select: function(info) {
//console.log(info);
calendar.addEvent({ "title": "Test", start: info.start, end: info.end })
calendar.unselect();
},
selectOverlap: false,
selectAllow: function(selectInfo) {
var stM = moment(selectInfo.start);
var enM = moment(selectInfo.end);
var diff = enM.diff(stM, "minutes");
console.log(diff);
if (diff > 20)
{
return false;
}
return true;
},
events: [
{ "title": "Existing event", "start": "2019-08-08 10:00", "end": "2019-08-08 10:20"},
{ "title": "Existing event", "start": "2019-08-08 13:20", "end": "2019-08-08 13:40"},
]
});
calendar.render();
});
Demo: https://codepen.io/ADyson82/pen/aeqJQg
2) This option is closer to your desired UI (from your 2nd screenshot) but is a bit more complicated to achieve. I also, personally, think it leaves your calendar looking cluttered, and making it harder to see where the free and busy slots are, but ultimately it's up to you how you want to implement it. This works by adding a second event source, containing a list of all currently free slots. These are then used to display the start time of each free slot in the centre of it. They are coloured differently from the existing events (indicating a busy slot), so that it's a bit easier to tell the difference.
Of course, this requires you to use your server-side code to calculate all the currently free slots in your database and use that information to populate the second event source. (In the demo the free slot data is static, but of course that will not work in a real application.)
document.addEventListener("DOMContentLoaded", function() {
var Calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: ["timeGrid", "interaction"],
header: {
left: "prev,next today",
center: "title",
right: "timeGridFourDay"
},
defaultView: "timeGridFourDay",
views: {
timeGridFourDay: {
type: "timeGrid",
duration: { days: 4 },
buttonText: "4 day"
}
},
slotLabelFormat: {
hour: "numeric",
minute: "2-digit",
omitZeroMinute: true,
meridiem: "short"
},
allDaySlot: false,
firstDay: 1,
minTime: "08:00:00",
maxTime: "20:00:00",
contentHeight: "auto",
slotDuration: "00:20:00",
displayEventTime: false,
eventClick: function(info) {
if (info.event.extendedProps.type == "free") {
calendar.addEvent({
title: "Test",
start: info.event.start,
end: info.event.end
});
info.event.remove(); //delete the "free slot" event
}
},
eventSources: [
{
id: "busy",
events: [
{
title: "Existing event",
start: "2019-08-08 10:00",
end: "2019-08-08 10:20"
},
{
title: "Existing event",
start: "2019-08-08 13:20",
end: "2019-08-08 13:40"
}
]
},
{
id: "free",
backgroundColor: "green",
events: [
{
title: "08:00",
start: "2019-08-08 08:00",
end: "2019-08-08 08:20",
type: "free"
},
{
title: "08:20",
start: "2019-08-08 08:20",
end: "2019-08-08 08:40",
type: "free"
},
{
title: "08:40",
start: "2019-08-08 08:40",
end: "2019-08-08 09:00",
type: "free"
},
{
title: "09:00",
start: "2019-08-08 09:00",
end: "2019-08-08 09:20",
type: "free"
},
{
title: "09:20",
start: "2019-08-08 09:20",
end: "2019-08-08 09:40",
type: "free"
},
{
title: "09:40",
start: "2019-08-08 09:40",
end: "2019-08-08 10:00",
type: "free"
},
{
title: "10:20",
start: "2019-08-08 10:20",
end: "2019-08-08 10:40",
type: "free"
},
{
title: "10:40",
start: "2019-08-08 10:40",
end: "2019-08-08 11:00",
type: "free"
},
]
}
]
});
calendar.render();
});
For this demo I only created handful of the "free" slots (because it was tedious to create them), but hopefully you can get the idea of how it would start to look with dozens of them all over the calendar. Of course again you can amend the CSS to your requirements.
Demo: https://codepen.io/ADyson82/pen/JgpNEX
(You can of course amend the CSS of this further to make it appear more like your desired look and feel.)
Addendum: Here's the OP's final version, for anyone who is interested in the end product - based on taking the above suggestions into consideration: https://codepen.io/hugo-trial/pen/rXdajv
I want fullCalendar to go to one a specifical day, but when I call
$('#calendarContainer').fullCalendar('gotoDate', date);
It only increment the view of the actual date by one.
My variable date is
var date =$.fullCalendar.moment(moment.utc(app.mCurrentStartDate).format('YYYY-MM-DD'));
My only way to make it work was to do
for (var i = 0; i < 100; i++)
{
$('#calendarContainer').fullCalendar('gotoDate', date);
}
But that is not possible.
My calendar use custom views
views: {
agendaThreeDay: {
type: 'agenda',
duration: { days: 3 },
buttonText: '3 day',
columnFormat: 'dddd D MMMM',
},
agendaTwoDay: {
type: 'agenda',
duration: { days: 2 },
buttonText: '2 day',
columnFormat: 'dddd D MMMM',
}
},
Do you know if this is the intented behaviour of gotoDate, or may be I use it the wrong way ?
Thanks.
I have a kendo scheduler and I'm having a problem with move event. I can move only one event at a time and then I can't even grab any event afterwards. I think there's something wrong with the dates but I really can't figure out why. I tried dataSource with 2-3 events and it's working but when I put that exact same data in php and return it as json. It's not working.
Any help would be appreciated.
$("#scheduler").kendoScheduler({
date: new Date(),
startTime: new Date(today2()),
timezone: "Etc/UTC",
currentTimeMarker: false,
height: 800,
views:
[
"week",
{ type: "month", selected: true, eventHeight: 60}
],
dataSource:
{
transport:
{
read:
{
url: "tasks.php",
dataType: "json"
},
batch: true,
parameterMap: function (options, operation)
{
if (operation === "read") {
var scheduler = $("#scheduler").data("kendoScheduler");
var result =
{
start: scheduler.view().startDate(),
end: scheduler.view().endDate()
}
return kendo.stringify(result);
}
return kendo.stringify(options);
}
},
schema:
{
model:
{
id: "taskId",
fields:
{
taskId: { type: "number", from: "TT_CODE" },
start: { type: "date", from: "TT_START_DATETIME"},
end: { type: "date", from: "TT_END_DATETIME"},
title: { from: "TT_EDIT"}
}
}
}
}
});
php file with json data:
$json[0]['TT_CODE'] = 1;
$json[0]['TT_START_DATETIME'] = "2016-01-16 15:00:00";
$json[0]['TT_END_DATETIME']= "2016-01-16 16:00:00";
$json[0]['TT_EDIT'] = "Fast and furious 6";
echo json_encode($json);
Since you specified start and end as date in your model, the scheduler is expecting to received properly formatted date. While JSON passes date as string, javascript still expect the date string to be formatted.
In your case, it would be:
$json[0]['TT_CODE'] = 1;
$json[0]['TT_START_DATETIME'] = "2016-01-16T15:00:00.000Z";
$json[0]['TT_END_DATETIME']= "2016-01-16T16:00:00.000Z";
$json[0]['TT_EDIT'] = "Fast and furious 6";
You could also leave date as is and handle the string with a custom logic in the parameterMap function.
As a side note, if you have a doubt about the type formatting, go in the browser console and have a look at the network tab. You'll be able to compare the data sent by the working service to the data sent by PHP and see where is the difference.
Like others I'm having problems getting timed events to show up on the agendaWeek view. If you look at the events below, the first two are mine and show up as all day events. The last one is from the documentation and shows up in the correct time block. I've been staring at this so long I'm sure I'm missing something simple. Can anyone else see it?
$(document).ready(function() {
$("#calendar").fullCalendar({
defaultView: 'agendaWeek',
month:0,//current year assumed, first day of month assumed
date: 4,
height: 650,
header: {left: 'title',center:'agendaWeek'},
events: [
{
title : 'Fred',
start : '2010-01-04 08:00:00',
end : '2010-01-04 09:00:00',
allday : false
},
{
title : 'Betty',
start : '2010-01-06 08:00:00',
allday : false
},
{
title : 'event3',
start : '2010-01-05 12:30:00',
allDay : false // will make the time show
}
]
});
});
</script>
I fixed my problem as follows: Where you have allday you need allDay with a capital D.
Cheers!