Uncaught TypeError: start.getDate is not a function - javascript

I am working on an appointment system with full calendar. I want when an array of dates are selected, the values of those dates will be echoed on a div for the user to see his selected dates and can also unselect the dates.
I have been trying to console.log selected dates but I get the above error. It is becoming impossible for me to move ahead.
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
start: 'title',
center: '',
end: ''
},
initialView: 'dayGridMonth',
selectable: true,
select: function(date, jsEvent, view) {
date: date.getDate();
backgroundColor: 'green';
console.log('Selected: ' + date);
},
)
};
I have added date.toString() but it is not working. I have tried to use start and end of date but still not working as expect

Reading the documentation I see that the select function should accept one parameter. For example:
select: function(selectionInfo){
... // then here you can have: selectionInfo.start
}

Related

Fullcalendar external drag & drop does not work correctly

I am trying to implement a Fullcalendar functionality like so: an external event is dragged to the calendar, then the event is saved to the database via ajax, with its title, start and end dates.
I did achieve making the event title and start date/time to be saved to the DB, however I cannot fix the following couple of issues:
Currently, the end date/time saved to the DB is the same as the start date/time.
How do I make the end date to be 24h after the start date for all day events?
How do I get the exact start and end dates for a fixed duration event?
Once the event is dragged and saved to the DB, I cannot drag-drop any more events until I hit F5
My HML is the following:
<div id='external-events'>
<div class="fc-events-container">
<div>All Day Events</div>
<div class='fc-event' data-color='#28A745'>All Day Event</div>
<div>Fixed Duration Events</div>
<div class='fc-event' data-color='#50C1E9'>Event From 8am till 5 pm</div>
</div>
</div>
JQuery:
$('#external-drag').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
editable: true,
droppable: true,
defaultDate: new Date(),
selectable: true,
events: "../../ajax/get_events.php",
drop: function( date, allDay, jsEvent, ui ) {
var start = date.format();
var end = date.format();
var title = $.trim($(this).text());
$.ajax({
url: '../../ajax/add_event.php',
data: 'title='+ title+'&start='+ start +'&end='+ end,
type: "POST",
success: function(json) {
alert('Added Successfully');
},
error: function() {
alert('Error');
}
});
calendar.fullCalendar('renderEvent',
{
title: title,
start: start,
end: end,
allDay: allDay
},
true
);
}
});
Firstly, some background context to what you're experiencing: although you've labelled your second event as "from 8 to 5pm", that has no actual practical effect. If you drop either of your draggable items onto a time-aware calendar view (e.g. week view) then it will gain a start date and time. On a view such as month, which has no concept of specific times of day, then it will just gain a start date, without a time attached.
However in both cases, there is no end date. Once you add the event to the calendar via renderEvent, then fullCalendar will assign it a default duration (as per the
defaultAllDayEventDuration or defaultTimedEventDuration settings, as appropriate). You can use that to work out the notional end date (although the event object doesn't actually have its end property set unless you set forceEventDuration to true).
Now to a solution:
If you want to control it so that specific dragged items have pre-defined times, you would have to specify the time data in the data- properties of the relevant draggable items. Then you need to get those values in your drop callback, the same way as you do with the title, and use them when creating your event.
It took a bit of fiddling to get to this point, especially with the moment objects, but it now appears to do what you want - as far as I understand it.
drop: function(date, jsEvent, ui) {
var element = $(this);
var title = $.trim(element.text());
var color = element.data("color");
var start = moment(date.format()); //lose the extended fullCalendar moment with its "ambiguously-timed" feature, which gets in the way here
var end = start.clone();
var allDay = true;
console.log(start.format(), end.format());
if (typeof element.data("starttime") !== 'undefined') {
//timed events
var starttime = moment.duration(element.data("starttime"));
var endtime = moment.duration(element.data("endtime"));
start.set({ "hour": starttime.hours(), "minute": starttime.minutes()});
end.set({ "hour": endtime.hours(), "minute": endtime.minutes()});
allDay = false;
console.log(starttime.hours());
} else {
//allday events
end.add({ days: 1 });
}
console.log("title=" + title + "&start=" + start.format() + "&end=" + end.format());
$.ajax({
url: '../../ajax/add_event.php',
data: 'title='+ title+'&start='+ start.format() +'&end='+ end.format(),
type: "POST",
success: function(json) {
alert('Added Successfully');
},
error: function() {
alert('Error');
}
});
calendar.fullCalendar(
"renderEvent",
{
title: title,
start: start,
end: end,
color: color,
allDay: allDay
},
true
);
}
Demo: https://codepen.io/ADyson82/pen/GRRXwRL?editors=1010
N.B. Note that if a user drags an event onto a time-aware view like the week view, it will still create the events exactly as per the settings in the draggable, and will ignore whatever time of day they dropped it on. It's possible this could be confusing or irritating to some users - but I guess it depends what you're trying to achieve exactly.
P.S. I don't know where you got the idea that the drop callback has an allDay parameter. It's clearly not there in the documentation. You can't use that, so I've removed it in my version.

Change date range to show events in FullCalendar

I need to be able to set a "date range" with FullCalendar, using the "List" view. By date range, I mean being able to enter using 2 text fields, 2 different dates, for example :
Text field 1 : 2018-05-05
to
Text field 2 : 2018-05-06
And to filter the content of the calendar, using the List view to display the result, and show events that matches that date range.
Here's my code for the FullCalendar part:
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'listMonth, month,agendaWeek,agendaDay'
},
defaultView: 'listMonth',
locale: 'fr',
contentHeight: 600,
navLinks: true, // can click day/week names to navigate views
selectable: false,
eventRender: function(event, element, view) {
element.find('.fc-widget-header').append("<div style='color:#fff'>Conférencier choisi</div>");
element.find('.fc-title').append("<br/>" + event.lieu);
element.find('.fc-list-item-title').append("<br/>" + event.lieu);
element.find('.fc-list-item-title').append("<a href='" + event.lienconferencier + "'><div class='conferencier-calendrier-container'><div style='float:left;background-image:url(" + event.photoconferencier + ");width:40px;height:40px;background-size:cover;border-radius:100px;'></div><div style='float:left;padding-left:5px;font-weight:normal;'><strong>Conférencier</strong><br>" + event.conferencier + "</div></a>");
return ['all', event.status].indexOf($('#filter-status').val()) >= 0 &&
['all', event.client].indexOf($('#filter-contact').val()) >= 0 &&
['all', event.conferencier].indexOf($('#filter-conferencier').val()) >= 0 &&
['', event.numero].indexOf($('#numero').val()) >= 0;
},
selectHelper: true,
editable: false,
eventLimit: true, // allow "more" link when too many events
events: [
{
title: 'Example',
start: '2018-05-05',
end: '2018-05-06',
color: '#ff0000',
lieu: 'Montreal',
numero: '300445',
conferencier: 'John Doe',
photoconferencier: 'http://www.example.com/img/profile.jpg',
lienconferencier: 'http://www.example.com/profile/link.html',
url: 'http://www.google.com'
},
{
title: 'Example2',
start: '2018-05-08',
end: '2018-05-010',
color: '#ff0000',
lieu: 'New York',
numero: '300446',
conferencier: 'Steve Jobs',
photoconferencier: 'http://www.example.com/img/profile2.jpg',
lienconferencier: 'http://www.example.com/profile/link2.html',
url: 'http://www.apple.com'
},
],
});
And here's my text fields code:
<input type="text" placeholder="Date : From" id="start_date">
<input type="text" placeholder="Date : To" id="end_date">
I think I would have to add something like this:
$('#start_date').on('change', function () {
$('#calendar').fullCalendar('rerenderEvents');
});
$('#end_date').on('change', function () {
$('#calendar').fullCalendar('rerenderEvents');
});
But I am not sure. Also, please keep in mind that there's other filters too. Hence the "eventRender" part in the code with a bunch of stuff. So I need to make sure that "dateRange" filter won't break the other filters.
I read about "visibleRange" on FullCalendar's website, but I do not understand how I can make it work based on what is entered in the 2 "date range" text fields. I think also disabling the other views that I have set (to show the result in the List view only), would be a good idea.
Any idea how I can make it work? I'm kind of lost here.
Thanks a lot
EDIT :
I have tried this code:
$('#start_date').on('change', function () {
$('#calendar').fullCalendar('changeView', 'list', {
start: 2018-05-10,
end: 2018-05-30
});
});
Which is working. Basically, what it does is that I enter a new date in a text field with the ID of "start_date" (which uses a datepicker script, to that's why I went with "on change"), it changes the view to the list view, which is great, and displays only the events between the date I have entered. So to make it dynamic, I did this :
$('#start_date').on('change', function () {
var start_date = $('#start_date').val();
var end_date = $('#end_date').val();
$('#calendar').fullCalendar('changeView', 'list', {
start: start_date,
end: end_date
});
});
I have 2 fields, "start_date", and "end_date".
I thought that setting the "start" and "end" option in the changeView code for FullCalendar would update automatically everytime I select a new date, but it doesn't work. In fact, it works partially. If I enter the "end_date" first, then the "start_date", it will filter and work perfectly, showing the right date range. But after that, I cannot change it for another dateRange by changing the dates in the fields.
It acts like this probably because my function is "on change", based on the "#start_date" element. So I have to select the end_date first, to make sure it filters and change the view with something in the "end" option.
Any idea what I am doing wrong?
Thanks
EDIT 2 :
I tried changing the function from a "change" event to "click", and adding a "search" button. There's 2 issues here.
1 - It works only once. If I make a search, then change the date, and click again on the "#search-range" button, it won't do anything.
2 - When it works (first time after page load), if I select from May 1rst to May 5th for example, it will show the range from May 1rst to May 4th, for some reasons. Here's my code again :
$('#search-range').on('click', function () {
var start_date = $('#start_date').val();
var end_date = $('#end_date').val();
$('#calendar').fullCalendar('changeView', 'list', {
start: start_date,
end: end_date
});
});
Any ideas what's going on?
Thanks again
You're probably looking for the validRange option.
$('#start_date').on('change', function(){
$('#calendar').fullCalendar('option', 'validRange', {
// Don't worry if user didn't provide *any* inputs.
start: this.value,
end: $('#end_date').val()
});
});
$('#end_date').on('change', function(){
$('#calendar').fullCalendar('option', 'validRange', {
// Don't worry if user didn't provide *any* inputs.
start: $('#start_date').val(),
end: this.value
});
});
Demo: https://jsfiddle.net/8wd7sxyv/
UPDATE
The end date is now inclusive. So if end date is 2018-05-31, events on that day are included — the default behavior only includes up to 2018-05-30.
If the start and end dates are in same month, view is listMonth; otherwise, it is listYear.
function filterByDateRange(start_date, end_date, format) {
var s = $.fullCalendar.moment(start_date),
e = $.fullCalendar.moment(end_date),
v = $('#calendar').fullCalendar('getView'),
a, b;
// Start date is invalid; set it to the start of the month.
if (! s.isValid()) {
b = e.isValid();
s = b ? e.clone() : $.fullCalendar.moment();
s.date(1);
$('#start_date').val(s.format(format));
a = true;
}
// End date is invalid; set it to the end of the month.
if (! e.isValid()) {
b = s.isValid();
e = b ? s.clone() : $.fullCalendar.moment();
e.date(e.daysInMonth());
$('#end_date').val(e.format(format));
a = true;
}
// Start date is after end date; set it to a day before the end date.
if (s.isAfter(e)) {
s = e.clone().add('-1', 'day');
$('#start_date').val(s.format(format));
// End date is before start date; set it to a day after the start date.
} else if (e.isBefore(s)) {
e = s.clone().add('1', 'day');
$('#end_date').val(e.format(format));
}
// Add 1 day so that `end_date` is inclusive.
e = e.isValid() ? e.add('1', 'day') : e;
$('#calendar').fullCalendar('option', 'validRange', {
start: s.isValid() ? s : null,
end: e.isValid() ? e : null
});
a = a || s.isSame(e, 'month');
// If months are different, switch to the year list.
if ('listYear' !== v.name && ! a) {
$('#calendar').fullCalendar('changeView', 'listYear');
// Otherwise, switch back to month list, if needed.
} else if ('listMonth' !== v.name) {
$('#calendar').fullCalendar('changeView', 'listMonth');
}
}
$('#start_date').on('change', function(){
filterByDateRange(this.value, $('#end_date').val(), 'YYYY-MM-DD');
});
$('#end_date').on('change', function(){
filterByDateRange($('#start_date').val(), this.value, 'YYYY-MM-DD');
});
Demo: https://jsfiddle.net/8wd7sxyv/6/

selecting a day from UICalendar

I am fairly new to angular I am trying to implement a calendar using ui-calendar. So far I have been able to display a very basic calendar and some events on it.
Now I need to be able to click on a day and display the detailed events on a side tab. I seem to be lost on how to achieve this clicking day thing. This may seems very naive, I thought i'd find the html for each day cell on the calendar, and then it would be as easy as attaching a ng-click to it. But I cant seem to find any template where the html for calendar is. All I can see is the directive, which doesnt help much. I dont understand jquery at all, so I am really struggling to find any answers too.
To sum things up, I just want to know how to make a day on calendar clickable.
Thanks in advance.
code:
$scope.uiConfig = {
calendar: {
height: 450,
editable: true,
header: {
left: 'title',
center: '',
right: 'today prev,next'
},
eventClick: $scope.alertOnEventClick,
eventDrop: $scope.alertOnDrop,
eventResize: $scope.alertOnResize,
eventRender: $scope.eventRender,
dayClick: function(date, jsEvent, view) {
console.log("inside dayClick");
alert('Clicked on: ' + date.format());
var events = myCalendar.fullCalendar('clientEvents', function(event) {
return event.start.isSame(date) || event.end.isSame(date) || date.isBetween(event.start, event.end); // Will return all events starting/ending on this date or overlapping this date
});
}
}
};
In your configuration variable you can add a dayClick callback , in this callback you can do something like this:
dayClick: function( date, jsEvent, view ) {
var events = myCalendar.fullCalendar('clientEvents', function(event) {
return event.start.isSame(date) || event.end.isSame(date) || date.isBetween(event.start, event.end); // Will return all events starting/ending on this date or overlapping this date
});
}
This will return all the events that either are on this day or overlap it.
FullCalendar docs can be found here.

2 Bootstrap Datepickers: How to change min and max dates?

I have 2 datepickers on my webpage: One for the arrival date and the other for departure.
Now I'd like to set the min and max dates, according to the user selection.
2 Examples of what I want to achieve:
User selects 29.03.2015 as arrival -> departure's min date is set
accordingly.
User selects 29.03.2015 as departure -> arrival's max
date is set accordingly.
At the moment I am initializing the datepickers like so:
var startDate = "<?php echo date('d.m.Y'); ?>"; // Today
$('#startDate.input-group.date').datepicker({
format: "dd.mm.yyyy",
language: "de",
multidate: false,
todayHighlight: true,
startDate: startDate,
weekStart: 1
}).on('changeDate', function(e){
changeDate(e);
});
$('#endDate.input-group.date').datepicker({
format: "dd.mm.yyyy",
language: "de",
multidate: false,
todayHighlight: true,
startDate: startDate,
weekStart: 1
});
You notice the .on() function on the first datepicker. This is my current attempt to set the date of the 2nd one:
function changeDate(e){
$('#endDate.input-group.date').datepicker('setStartDate', e);
}
However this leaves me with the following error:
Uncaught TypeError: undefined is not a function: bootstrap-datepicker.js:1493
The line in question is this:
parts = date.match(/([\-+]\d+)([dmwy])/g)
Can you please give me a hint on what I am doing wrong and on how I can achieve said effect?
if you console.log changing like this:
.on('changeDate', function(e){
console.log(e);
});
you'll see the event returns an event object;
you should try passing something like e.date (but be sure to format the string accordingly to your startDate format).
Here's more about the extra data attached to the event object : http://bootstrap-datepicker.readthedocs.org/en/latest/events.html

jQuery FullCalendar- Default end time for dropped events

I am using FullCalendar with the ability to drop external events onto the calendar:
http://arshaw.com/js/fullcalendar-1.5.2/demos/external-dragging.html
When a new event is dropped, it has a start time but no end time. It seems that all these events are "all day" events by default. I tried changing the allDay callback to false:
http://arshaw.com/fullcalendar/docs/dropping/drop/
...but it hasn't helped. I'm trying to get it to where when a new event is dropped onto the calendar, it's end time is set for 30 minutes after the drop time (ie. the setting of my defaultEventMinutes)
http://arshaw.com/fullcalendar/docs/agenda/defaultEventMinutes/
Anyone know how to do this?
Here is my current fullcalendar function:
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'agendaWeek,agendaDay'
},
events: {
url: 'json-events.php',
type: 'POST',
data: {
},
error: function() {
alert('there was an error while fetching events!');
},
},
allDaySlot: false,
defaultView: 'agendaWeek',
slotMinutes: 15,
firstDay: '<?php echo $config->week_start; ?>',
minTime: '<?php echo $config->day_start; ?>',
maxTime: '<?php echo $config->day_end; ?>',
defaultEventMinutes: 30,
aspectRatio: 1.1,
titleFormat: {
month: 'MMMM yyyy',
week: "MMMM dd[ yyyy]{ '—'[ MMMM] dd, yyyy}",
day: 'dddd MMM dd, yyyy'
},
columnFormat: {
month: 'ddd', // Mon
week: 'ddd M/dd', // Mon 9/07
day: 'dddd M/dd' // Monday 9/07
},
editable: true,
droppable: true,
drop: function(date, allDay) {
var originalEventObject = $(this).data('eventObject');
var copiedEventObject = $.extend({}, originalEventObject);
copiedEventObject.start = date;
//copiedEventObject.allDay = allDay; // Can I make this 30min by default drop?
copiedEventObject.end = (date.getTime() + 1800000)/1000;
copiedEventObject.group_id = $(this).attr("name"); // Group ID
addEvent(copiedEventObject); // Add the event to the db
$('#calendar').fullCalendar('renderEvent', copiedEventObject, true);
if ($('#drop-remove').is(':checked')) {
$(this).remove();
}
}
});
I was looking for the same thing, for FullCalendar v2, and I found out this:
defaultTimedEventDuration
A fallback duration for timed Event Objects without a specified end value.
Duration, default: '02:00:00' (2 hours)
If an event does not have an end specified, it will appear to be this duration when rendered.
The actual end of the event will remain unset unless forceEventDuration has been set to true.
This setting only affects events with allDay equal to false. For all-day events, use defaultAllDayEventDuration.
So you just need to do something like this, to have a default duration of 30 min.
$('#calendar').fullCalendar({
defaultTimedEventDuration: '00:30:00',
forceEventDuration: true,
...
...
});
You can set the end time of the dropped event in the drop function. One thing to note is that for Full Calendar, time will be measured in seconds.
var arrayOfEvents = [];
$('#calendar').fullCalendar({
...
drop: function(date) {
...
// retrieve the dropped element's stored Event Object
var originalEventObject = $(this).data('eventObject');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = date;
copiedEventObject.end = (date.getTime() + 1800000)/1000; // put your desired end time here
copiedEventObject.allDay = false;
// Push the event into the array
arrayOfEvents.push(copiedEventObject);
...
},
...
)};
I'm using this:
$('#calendar').fullCalendar({
allDayDefault: false
});
and at every event you will have display only start time ...
using Mr. J4mes answer, the event reverts back for me as well, it does not render.
The following helps: populate copiedEventObject.end with a new Date(...):
copiedEventObject.end =new Date(date.getTime()+900000);
This adds 15 minutes (=900000 millisecs) to the start time
I have found the same problem. The solution is to setup a start/end property on the DOM object that is stored within the item that is going to be dropped.
E.g.
$('#external-events div.external-event').each(function() {
// create an Event Object (http://arshaw.com/fullcalendar/docs/event_data/Event_Object/)
// it doesn't need to have a start or end
// use the element's text as the event title
// set a start and end placeholder for the object!
var eventObject = {
title: $.trim($(this).text(), start: null, end: null)
};
I resolved this problem using
defaultTimedEventDuration: '01:00',
forceEventDuration: true,
From docs: https://fullcalendar.io/docs/forceEventDuration
https://fullcalendar.io/docs/v3/defaultTimedEventDuration
If an event’s end is not specified, it will be calculated and assigned to the Event Object using defaultTimedEventDuration or defaultAllDayEventDuration.

Categories