How to remove an unsaved event? - javascript

I am using jquery and fullcalendar to schedule activities. When users select a timeslot, a form is shown on the right of the calendar where they can enter additional details.
With the 'select' callback I render a temporary event on the calendar so my users will have visual feedback while filling out the form.
However, when they have misselected a timeslot, they are able to select a new timeslot. This however renders a second (and possibly a third, fourth...) event on the calendar.
I thought I would be able to use the 'eventAfterRender(event, element)' callback to element.siblings().remove(), but this failed as eventAfterRender is called for every event on the calendar with every renderEvent.
Maybe there is a callback or method that I am missing, but as I see it, there is no easy way to remove an "unsaved" event.
Below is some sample code.
var fullCal = '';
$(function() {
fullCal = $('#fullcalendar').fullCalendar({
// options
select: SelectDate,
eventAfterRender: function(event, element) {
// this does not work as it simply just keeps the last event in the DOM.
element.siblings().remove()
},
viewDisplay: UnselectDate // hides and clears the form, intended behavior
});
});
function SelectDate(startDate, endDate, allDay, jsEvent, view) {
$('#BijlesForm').show();
var BijlesEvent = {start: startDate, end: endDate, title: 'Bijles', allDay: false};
fullCal.fullCalendar('renderEvent', BijlesEvent);
//fill the form
}

Okay, silly silly me. It must've been the fatigue or something, but I found how to do it on my own.
I removed the eventAfterRender callback and changed my SelectDate function to this:
function SelectDate(startDate, endDate, allDay, jsEvent, view) {
$('#BijlesForm').show();
fullCal.fullCalendar( 'removeEvents', 'unsaved' )
var BijlesEvent = {start: startDate, end: endDate, title: 'Bijles', allDay: false, id: 'unsaved'};
fullCal.fullCalendar('renderEvent', BijlesEvent);
}
This works like a charm. Is this also the preferred way of doing things, or should it be done differently?

Related

How add events in fullcalendar without wait for database adding

I figured out how to add en event quickly in fullcalendar, The idea is add to calendar, display and after save to database, without wait for database, but then events recently added gets duplicate when going back a week and comeback.
The code for add the event to calendar is this:
// First add the event to calendar, displaying almost instantly.
var idTemp = Math.floor(Math.random() * 100000) + 1;
var event = {
id: idTemp,
title: TextoEvento,
start: CalendarInfoSelect.start,
end: CalendarInfoSelect.end,
allDay: false,
tituloOriginal: TextoEvento,
backgroundColor: colorEvento,
textColor: colorEventoTexto
};
calendar.addEvent(event );
// Then, add to database:
$.ajax({
cache: false,
url: '#Url.Action("EventAddedTareaReciente", "CH")',
type: "POST",
dataType: 'json',
data: {
id: Idbd,
idAct: IdAct,
idProy: IdProy,
idProd: IdProd,
newStart: CalendarInfoSelect.startStr,
newEnd: CalendarInfoSelect.endStr,
ini: CalendarInfoSelect.start.toISOString(),
fin: CalendarInfoSelect.end.toISOString()
},
success: function (data) {
if (data.Id > 0) {
event = calendar.getEventById(idTemp);
// Here set id with database's one
event.setProp('id', data.Id);
}
else {
event = calendar.getEventById(idTemp);
event.remove();
}
},
error: function (xhr) {
event = calendar.getEventById(idTemp);
event.remove();
}
});
There is no error here it's works fine.
But when the user click to got one week back and comeback to the original week the event gets duplicate.
If the user add several event this ways this events gets duplicate in calendar.But they are not duplicate in database when refresh browser (F5) the display it's perfectly fine.
It's like the events add this way get sticky in memory.
Any help, ideas? I can't find a solution. Maybe there is another way to do that.
I use FullCalendar Core Package v4.3.1
Thanks
As per https://fullcalendar.io/docs/v4/Calendar-addEvent, if you specify an event source for the event to belong to (logically, it should be the same source you fetch your events from when receiving them from the database), then when the source is re-fetched (e.g. such as when the calendar date changes) it will clear the locally-added event from the calendar.
If you didn't define a specific event source when setting up the calendar, now would be a good time to modify your options slightly to support this - see https://fullcalendar.io/docs/v4/eventSources and https://fullcalendar.io/docs/v4/event-source-object
Example:
Event source is defined in the calendar configuration:
eventSources: [{
id: 1,
url: '/events'
}]
Event manually added to the calendar is associated with the event source:
calendar.addEvent(event, 1);

fullcalendar: is there a way to call dayRender only after i load my events via events function

i'm using fullcalendar in a web application i"m building.
i load my events with events function and ajax.
here is my code:
var ajaxData;
var eventsJsonArray;
var json_backgrundColor;
var json_iconstring;
//alert('Hello! 1!');
$(document).ready(function () {
$('#calendar').fullCalendar({
header: {
left: 'prev',
center: 'title',
right: 'next,month,agendaWeek,agendaDay'
},
//custom events function to be called every time the view changes
events: function (start, end, timezone, callback) {
var mStart = start.format('M')
var yStart = start.format('YYYY')
$.ajax({
url: '$getMonthDataUrl',
type: 'GET',
data: {
startDate: start.format(),
endDate: end.format()
},
error: function () {
alert('there was an error while fetching events!');
},
success: function (data) {
alert('nice!!');
ajaxData = data;
json_iconstring = ajaxData['iconString'];
json_backgrundColor = ajaxData['Calendar_cell_background_color'];
eventsJsonArray = ajaxData['all_Events_For_The_Month'];
callback(eventsJsonArray); //pass the event data to fullCalendar via the supplied callback function
}
});
},
fixedWeekCount: false,
showNonCurrentDates: false,
dayRender: function (date, cell, view) {
console.log(json_backgrundColor);//this brings eror because json_backgrundColor is undefined
var cellDate = date.format('D');
if (date.format('M') == view.start.format('M')) //cheacking is this day is part of the currrent month (and not prev/next month)
{
alert(cellDate);
cell.css('background-color', json_backgrundColor[cellDate]);//this brings eror because json_backgrundColor is undefined
}
},
})
});
when i load my events via ajax i'm also getting the information about which background color each cell should get. i can only get this info via the events ajax request.
the problem is that when the dayRender is running, i still don't have the background color data. (json_backgrundColor is undefined).
is there a way that dayRender will run after the events calendar will stop running? or any other code that will fix my problem.
many thanks!!
Your problem is that the "dayRender" callback runs after the view is changed (changing the date using prev/next counts as changing the view, for this purpose), but before the events for the new view have been downloaded and rendered. That's why your json_backgrundColor array is undefined.
Since you mentioned that the colour to be used depends on the exact nature of the events currently scheduled for that specific day, we need to find something that we can run after all the events, and this colour data, have been downloaded.
Inspecting the HTML, we can see that the table cells used to draw each day all have the CSS class "fc-day" applied. They also have a data-date property containing the day that they relate to. Finally, days that are disabled (outside the main month, due to you setting showNonCurrentDates:false) have an extra class of "fc-disabled-day" applied. We can use these pieces of information to identify the cells we want to change, without having to use the dayRender callback.
The eventAfterAllRender callback runs once when all the events have been rendered. Therefore this seems like a good place to alter the background colours of the cells:
eventAfterAllRender(function(view) {
//loop through each non-disabled day cell
$('.fc-day:not(.fc-disabled-day)').each(function(index, element) {
//set the background colour of the cell from the json_backgroundColor arrray, based on the day number taken from the cell's "data-date" attribute.
$(this).css('background-color', json_backgroundColor[moment($(this).data("date")).format("D")]);
});
}
Note that I have renamed json_backgrundColor to json_backgroundColor to correct the spelling error.
N.B. This is brittle in the sense that it relies on the class names that fullCalendar uses internally to represent the day cells. If fullCalendar decides to do this differently in a future release, it will break (whereas if we were able to use the fullCalendar API via the designated callbacks, they would likely maintain consistency despite internal changes, or at least document any change). But it's pretty key to the Month view, so realistically it's not likely to change any time soon - you would just have to remember to test it if you update your fullCalendar version.
if anyone still wondering you can use dateSet option like
datesSet: event => {
var from = moment(event.start).format('YYYY-MM-DD');
var to = moment(event.end).format('YYYY-MM-DD');
dateStatus = getEachDateStatus(from, to);
//{'2022-11-10' : 'fullbooked', '2022-11-09' : 'halfBooked'};
Object.keys(dateStatus).forEach(key => {
$('td[data-date="'+key+'"]').addClass(dateStatus[key]);
});
},
Instead of relying on dayRender, you should create background color events based on your ajax:
events = [
...
{ date: date
color: ...
rendering: 'background'
className: 'my-class'
}]
You can transform events using css any way you like, with or without the rendering: 'background' option.

fullcalendar - date format for end/start events

This (I hope) is a basic question. I'm not seeing calendar events in fullcalendar, and I believe the issue is the date format I am attempting to use for start/end events. I am attempting to setup a basic calendar by loading JSON events. Here is my JSON output (trimmed to one event so as not to take up much room):
[{"id":"89","title":"A Title","start":"June 2nd 2015","end":"August 14th 2015"}]
My javascript looks like this:
$(document).ready(function() {
$('#calendar').fullCalendar({
editable: false,
events: "data.php"
});
});
Again, very basic. I know for certain that the issue for the events not appearing is due to the date format I am using, but I am not certain how to tell fullCalendar to use the MMMM Do YYYY format for start/end events with moment.js. Does anyone have advice on how this is accomplished?
EDIT:
Attempted to add something along these lines...but still no luck:
var start = moment(event.start).format("MMMM Do YYYY");
var end = moment(event.end).format("MMMM Do YYYY");
I'm not sure if this would be considered an answer or more of a workaround, but I'll post it as an answer anyway.
I ended up just converting the date format in the json output as Bruno had suggested in the above comment. Sort of wished I could have figured it out with the javascripting, but after hours of trying I could never get the events to display in the calendar.
I'll go ahead and post my php source for those curious (just showing the start date):
$start = $row['startdate'];
$start_obj = new \DateTime($start);
$events['start'] = $start_obj->format('Y-m-d');
I accomplished something similar by defining a function for the events, iterating through the data creating moment.js objects for the start field using my desired format. The docs have the basics for how to accomplish this.
EDIT: I copied the example from the docs and modified the start time using moment.js.
$('#calendar').fullCalendar({
events: function(start, end, timezone, callback) {
$.ajax({
url: 'myxmlfeed.php',
dataType: 'xml',
data: {
// our hypothetical feed requires UNIX timestamps
start: start.unix(),
end: end.unix()
},
success: function(doc) {
var events = [];
$(doc).find('event').each(function() {
events.push({
title: $(this).attr('title'),
start: moment($(this).attr('start'), 'MMMM Do YYYY') // will be parsed
});
});
callback(events);
}
});
}
});

angular-ui ui-calendar not updating on changes to Event Source Object / ng-model

I'm adding fullcalendar.js to an angular app using angular-ui / ui-calendar.
(angularjs 1.3.10, fullcalendar 2.2.6, ui-calendar 0.9.0-beta.1, jQuery 2.1.3, moment 2.9.0 & angular-moment 0.9.0)
In the calendar I'm using the dayClick as a datepicker type function to:
- write the selected date to scope (for other uses in the app)
- update the Event Source Object events array with the selected date
- display the selected date (ie newly updated event) on the calendar
I have no problems completing the 1st two tasks, but the 3rd is not updating automatically.
From the documentation:
An Event Sources objects needs to be created to pass into ng-model.
This object's values will be watched for changes. If a change occurs, then that specific calendar will call the appropriate fullCalendar method.
However it doesn't seem to be updating the calendar this automatically...
Is this a bug in ui-calendar or am I missing something ?
Interestingly if I have the calendar in an ng-if tab, and toggle between the tabs, the calendar updates correctly (after the toggle).
See this jsfiddle and:
- run, then select a date (notice the events array is updated correctly)
- toggle Tab 2 then back to Tab 1 - notice the date now displays correctly...
html looks like:
<div ui-calendar="uiConfig.calendar" ng-model="calendarDate" calendar="myCalendar1"></div>
Controller code looks like
myApp.controller('MainCtrl', function($scope, $filter, moment, uiCalendarConfig){
$scope.calendarDate = [
{
events: [
{
title: 'From',
start: '2015-01-31',
allDay: true,
rendering: 'background',
backgroundColor: '#f26522',
},
],
}
];
$scope.setCalDate = function(date, jsEvent, view) {
var dateFrom = moment(date).format('YYYY-MM-DD'); // set dateFrom based on user click on calendar
$scope.calendarDate[0].events[0].start = dateFrom; // update Calendar event dateFrom
$scope.dateFrom = $filter('date')(dateFrom, 'yyyy-MM-dd');; // update $scope.dateFrom
};
$scope.uiConfig = {
calendarFrom : {
editable : false,
aspectRatio: 2,
header : {
left : 'title',
center : '',
right : 'today prev,next'
},
dayClick : $scope.setCalDate,
background: '#f26522',
},
};
});
PS had a look at this question (which is similar) but was asked quite a few versions ago - plus the suggested solution calendar.fullCalendar('refetchEvents'); doesn't work since the calendar object is not defined - unsure what calendar.fullCalendar would be for my code...
That seems to be a problem with ui-calendar. I haven't been able to solve it so far. However, as a workaround, instead of updating the current event, you can create a new one: just replace $scope.calendarDate[0].events[0].start = dateFrom; by $scope.calendarDate[0].events.push({title: 'From', start: selectedDate, allDay: true, rendering: 'background', backgroundColor: '#f26522'});: http://jsfiddle.net/gidoca/kwsrnopz/.
On a side note, to access the calendar object to call the fullCalendar function, you would use $scope.myCalendar1 - ui-calendar adds it the the scope with a variable of the name given as the calendar attribute in the HTML.
I had the same issues but sorted out by two different ways.
When dynamically loaded the content through $http use uiCalendarConfig addEventSource
uiCalendarConfig.calendars['mycalendar'].fullCalendar('addEventSource', $scope.events);
Incase if calendar toggles visibility and hidden on load use refetchEvents
$timeout(function(){
uiCalendarConfig.calendars['mycalendar'].fullCalendar('refetchEvents');
})
$timeout holds the calendar to compile within the scope

How do I delete this event from FullCalendar?

The calendar lets the user drag a timeslot onto the calendar, however I would like them to be able to remove it if they click on it.
So in the eventClick I have this function:
function (calEvent) {
removeRequestedEvent($(this), calEvent);
},
It just passes in the calendar event and the calendar itself.
removeRequestedBooking: function (cal, calEvent) {
if (!confirm("Delete?"))
return;
cal.fullCalendar("removeEvents", calEvent.id);
cal.fullCalendar("rerenderEvents");
// Re-show draggable element
$("#requests #" + calEvent.id).show();
}
I've also tried using a filter, but a breakpoint on the return statement is never hit.
cal.fullCalendar("removeEvents", function (event) {
return event.id == calEvent.Id;
});
Any ideas? (I know the Id is right, and the last line works). Firebug doesn't show any errors in the javascript.
I'm using FullCalendar v1.4.10
When you have all your id's in place use Tuan's solution.
But when you do NOT have id's in your event do it like this (this work also when you have id's set):
eventClick: function(event){
$('#myCalendar').fullCalendar('removeEvents',event._id);
}
Why this problem appear?
The common reason for that is fullcalendar doesn't add id automatically when you're adding new event. If so, id which you have passed is undefined. Fullcalendar uses id in both cases when you're trying delete using id or filter. So when it's value is undefined it always return false. Meaning list of elements to delete is always empty.
Even simpler:
eventClick: function(calEvent, jsEvent, view) {
$('#calendar').fullCalendar('removeEvents', function (event) {
return event == calEvent;
});
}
Instead of using your passed in cal, can you try using a call to the div that holds your calendar?
In the case of eventClick, this refers to the HTML for the event according to what I'm reading in the docs.
Use refetchEvents:
cal.fullCalendar("refetchEvents");
Justkt's answer took me a second to wrap my head around, but I'll post my results for any other noobs who need to see the code in a really simple way:
eventClick: function(event){
var event_id = event.id;
$.post('/Dropbox/finance/index.php/welcome/update', {"event_id": event_id},
function(data){
$('#calendar').fullCalendar("removeEvents", (data));
$('#calendar').fullCalendar("rerenderEvents");
}
});
}
The PHP (using codeignighter):
public function update(){
$result = $this->input->post('event_id');
echo $result;
// would send result to the model for removal from DB, or whatever
}
I use filter function with event.start and it works well
calendar.fullCalendar('removeEvents', function(event) {
return
$.fullCalendar.formatDate(event.start, 'yyyyMMdd')
== $.fullCalendar.formatDate(start, 'yyyyMMdd');
});

Categories