Need help trying to make FullCalendar persistant through a postback - javascript

So I have a calendar displayed on one of my webform pages. Works great and serves purpose for end users. However to add/edit events I create a postback that resets the view to its default. Only an issue for the administrator but he will often will add entries a year or more in advance making this a nuisance.
To try and solve this I added a hidden textbox to store the start date of the calendar view.
<asp:TextBox ID="txtSaveTheDate" style="display:none;" runat="server"></asp:TextBox>
Then in each event I update the date to the current view. You will never get a postback unless you have triggered an event first)
eventClick: function (calEvent, jsEvent, view) {
document.getElementById('<%=txtSaveTheDate.ClientID%>').value = view.start.format();
...
},
I then use the defaultDate attribute to use this date to show the last shown date range in the calendar.
defaultDate: moment(SaveTheDate),
This works 80%.
When I click on the calendar to create an event the proper date moves into the textbox.
However, once the page postback The calendar return to one month before where it should. This happens if you are in the present, past or future. The only time it goes to the proper date is Jan 2023, for whatever reason that month works. The only clue is that the display starts on the 1st of the month unlike most.
Any Tips would be appreciated including alternate techniques.
Full procedure for reference.
jQuery(document).ready(function () {
SaveTheDate = document.getElementById('<%=txtSaveTheDate.ClientID%>').value;
if (SaveTheDate == '') {
SaveTheDate = new Date();
};
$.ajax({
type: "POST",
contentType: "application/json",
data: "{}",
url: "TrainingCalendar.aspx/GetEvents",
dataType: "json",
success: function (data) {
$('div[id*=fullcal]').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month'
},
defaultDate: moment(SaveTheDate),
displayEventTime: false,
events: $.map(data.d, function (item, i) {
var event = new Object();
event.id = item.EventID
event.start = new Date(item.StartDate);
event.end = new Date(item.EndDate);
event.title = item.EventName;
event.backgroundColor = item.Color;
event.textColor = item.TextColor;
return event;
}),
eventClick: function (calEvent, jsEvent, view) {
//Let's make sure they have permissions to edit the page
if (document.getElementById('<%=btnNotes.ClientID%>')) {
document.getElementById('<%=txtSaveTheDate.ClientID%>').value = view.start.format();
document.getElementById('<%=txtEventId.ClientID%>').value = calEvent.id;
document.getElementById('<%=txtEventName.ClientID%>').value = calEvent.title;
var date = new Date(calEvent.start);
document.getElementById('<%=txtDate.ClientID%>').value = ((date.getMonth() > 8) ? (date.getMonth() + 1) : ('0' + (date.getMonth() + 1))) + '/' + ((date.getDate() > 9) ? date.getDate() : ('0' + date.getDate())) + '/' + date.getFullYear();
$('#EventModal').modal('show');
}
},
dayClick: function (dt, jsEvent, view) {
//Let's make sure they have permissions to edit the page
if (document.getElementById('<%=btnNotes.ClientID%>')) {
document.getElementById('<%=txtSaveTheDate.ClientID%>').value = view.start.format();
document.getElementById('<%=ddlNewEventName.ClientID%>').value = '0';
document.getElementById('<%=txtNewEventName.ClientID%>').value = '';
document.getElementById('<%=txtNewDate.ClientID%>').value = dt.format('MM/DD/YYYY');
$('#NewEventModal').modal('show');
}
}
});
$("div[id=loading]").hide();
$("div[id=fullcal]").show();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
debugger;
}
});
});

So I have discovered by hardcoding some values that "defaultDate" needs to see the first day of the month's view, not the first day displayed in the view.
This will vary based on the version you are on but...
document.getElementById('<%=txtSaveTheDate.ClientID%>').value = view.start.format();
Returns the first date on the calendar
Changing from start to intervalStart gets you the first day of the month.
document.getElementById('<%=txtSaveTheDate.ClientID%>').value = view.intervalStart.format();
The syntax is different based on the version, intervalStart is compatible for version 3.
Here are the view objects available, you can select your version to change the content.
https://fullcalendar.io/docs/v3/view-object

Related

Moving $.get method to its own function to avoid repeating

I have the following function for pulling data from a php json_encode for use in FullCalendar.
eventDrop: function(info) {
$.get( "php/get-events.php", function( data ) {
// data is your result
// Find the value for editable where the event id = the event you are trying to move
rawdata = JSON.parse(data);
editable = rawdata.find(x => x.id === info.event.id).editable;
start= info.event.start.toISOString();
start = moment(info.event.start).format('Y-MM-DD HH:mm:ss');
end= info.event.end.toISOString();
end = moment(info.event.end).format('Y-MM-DD HH:mm:ss');
title = info.event.title;
id = info.event.id;
});
}
I will use very similar code for the eventResize function within fullcalendar, so I would like to extract this part
$.get( "php/get-events.php", function( data ) {
// data is your result
// Find the value for editable where the event id = the event you are trying to move
rawdata = JSON.parse(data);
into it's own function (not 100% sure I'm using the right terminology here?) I seen this answer jQuery - Passing variable within a function to another function about how to pass variables in the global scope, so I tried to move my above code out of eventDrop like so
$.get( "php/get-events.php", function( data ) {
// data is your result
// Find the value for editable where the event id = the event you are trying to move
rawdata = JSON.parse(data);
});
eventDrop: function(info) {
But this gives me an error
Uncaught SyntaxError: Unexpected token '.'
Ideally I would like to do the json extract using the $.get only one time throughout my page, and then reference the rawdata global variable to read the information, is this possible?
My full solution at current is
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var today = moment().day();
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
defaultDate: today,
editable: true,
$.get( "php/get-events.php", function( data ) {
// data is your result
// Find the value for editable where the event id = the event you are trying to move
rawdata = JSON.parse(data);
});
eventDrop: function(info) {
editable = rawdata.find(x => x.id === info.event.id).editable;
start= info.event.start.toISOString();
start = moment(info.event.start).format('Y-MM-DD HH:mm:ss');
end= info.event.end.toISOString();
end = moment(info.event.end).format('Y-MM-DD HH:mm:ss');
title = info.event.title;
id = info.event.id;
if (!confirm("Confirm you want to change " + info.event.title + " to " + info.event.start)) {
info.revert();
}
else{
if(editable === 'Y'){
$.ajax({
url: 'php/calendarupdate.php',
data: 'title=' + info.event.title + '&start='+ start +'&end=' + end + '&id=' + info.event.id ,
type: "POST"
});
}
else{
alert("Can only modify this calendar event if you created it. Please ask the event creator to modify.");
calendar.refetchEvents();
}
}
},
navLinks: true, // can click day/week names to navigate views
dayMaxEvents: true, // allow "more" link when too many events
events: {
url: '/php/get-events.php',
failure: function() {
document.getElementById('script-warning').style.display = 'block'
}
},
loading: function(bool) {
document.getElementById('loading').style.display =
bool ? 'block' : 'none';
}
});
calendar.render();
});
</script>
Problem solved, thanks to #Patrick Evans for the suggestion, I was adding the get call to the middle of my code, where I had to add it at the end, after the ";" to end the line. I can now reference "rawdata" variable within EventDrop.
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var today = moment().day();
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
defaultDate: today,
editable: true,
eventDrop: function(info) {
editable = rawdata.find(x => x.id === info.event.id).editable;
start= info.event.start.toISOString();
start = moment(info.event.start).format('Y-MM-DD HH:mm:ss');
end= info.event.end.toISOString();
end = moment(info.event.end).format('Y-MM-DD HH:mm:ss');
title = info.event.title;
id = info.event.id;
if (!confirm("Confirm you want to change " + info.event.title + " to " + info.event.start)) {
info.revert();
}
else{
if(editable === 'Y'){
$.ajax({
url: 'php/calendarupdate.php',
data: 'title=' + info.event.title + '&start='+ start +'&end=' + end + '&id=' + info.event.id ,
type: "POST"
});
}
else{
alert("Can only modify this calendar event if you created it. Please ask the event creator to modify.");
calendar.refetchEvents();
}
}
},
navLinks: true, // can click day/week names to navigate views
dayMaxEvents: true, // allow "more" link when too many events
events: {
url: '/php/get-events.php',
failure: function() {
document.getElementById('script-warning').style.display = 'block'
}
},
loading: function(bool) {
document.getElementById('loading').style.display =
bool ? 'block' : 'none';
}
});
$.get( "php/get-events.php", function( data ) {
// data is your result
// Find the value for editable where the event id = the event you are trying to move
rawdata = JSON.parse(data);
});
calendar.render();
});
</script>

How to update start Time(!) in fullcalendar.js

Is there a way to change the start time of an Event, wich I draged into the calendar.
The Event comes from an external Source like this:
//initialize the external events
$('#external-events .fc-event').each(function() {
/* // store data so the calendar knows to render an event upon drop
$(this).data('event', {
title: $.trim($(this).text()), // use the element's text as the event title
stick: true // maintain when user navigates (see docs on the renderEvent method)
});
*/
var eventObject = {
title: $.trim($(this).text()), // use the element's text as the event title
id: $(this).data('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({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
I want to change/update the start Time and Title - if necessary - of the Event in a modal Dialog. It seems to work fine, but everytime I add another Event by dragging and want to change it, it changes all other dragged Events, too.
eventClick: function(calEvent, jsEvent, view) {
//Sending data to modal:
$('#modal').modal('show');
$("#input_title").val(calEvent.title);
var my_time = moment(calEvent.start).format('LT');
$("#input_time").val(my_time);
var my_date = moment(calEvent.start).format("YYYY-MM-DD");
$("#input_date").val(my_date);
// waiting for button 'save' click:
$('.btn-primary').on('click', function (myEvent) {
calEvent.title = $("#input_title").val();
var my_input_time = $("#input_time").val();
var momentTimeObj = moment(my_input_time, 'HH:mm:ss');
var momentTimeString = momentTimeObj.format('HH:mm:ss');
var my_input_date = $("#input_date").val();
var momentDateObj = moment(my_input_date, 'YYYY-MM-DD');
var momentDateString = momentDateObj.format('YYYY-MM-DD');
calEvent.start = moment(momentDateString + ' ' + momentTimeString, "YYYY-MM-DD HH:mm");
$('#calendar').fullCalendar('updateEvent', calEvent);
$('#calendar').fullCalendar('unselect');
$('#modal').modal('hide');
});
}
What I am doing wrong?
I finally figured out, how to do this. In my example I'm able to change the event end-time by calculating the duration between start and end and diplay it as HH:mm. So the User can change the duration like 01:00 (hour). Also I add some additional fields like "information" and "color". After the changes in a modal (bootstrap) are made, I write it back to the calendar. Maybe there are better solutions for this, but for me it works fine.
// initialize the external events
$('#external-events .fc-event').each(function() {
// Start Time: String to Date
var my_start_time = new Date (new Date().toDateString() + ' ' + $(this).data('start'));
var start_time = moment(my_start_time).toDate();
// End Time: String to Date -> Date to Decimal
var my_dur_time = new Date (new Date().toDateString() + ' ' + $(this).data('duration'));
var dur_time = moment(my_dur_time).format('HH:mm');
dur_time = moment.duration(dur_time).asHours();
//Add Decimal End Time to Start Time
var end_time = moment(start_time).add(dur_time, 'hours');
// store data so the calendar knows to render an event upon drop
$(this).data('event', {
start: $(this).data('start'),
end: end_time,
title: $.trim($(this).text()), // use the element's text as the event title
stick: true, // maintain when user navigates (see docs on the renderEvent method)
});
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
$('#calendar').fullCalendar({
//Other calendar settings here ...
eventClick: function(event, element) {
curr_event = event;
var inp_start_time = moment(event.start).format();
var inp_end_time = moment(event.end).format();
var diff_time = moment(moment(inp_end_time),'mm').diff(moment(inp_start_time),'mm');
diff_time = moment.duration(diff_time, "milliseconds");
diff_time = moment.utc(moment.duration(diff_time).asMilliseconds()).format("HH:mm");
var my_time = moment(event.start).format('HH:mm');
var my_date = moment(event.start).format('DD.MM.YYYY');
var my_hidden_date = moment(event.start).format('YYYY-MM-DD');
$("#inp_time").val(my_time);
$("#inp_date").val(my_date);
$("#inp_hidden_date").val(my_hidden_date);
$("#inp_title").val(event.title);
$("#inp_duration").val(diff_time);
$("#inp_information").val(event.information);
$("#inp_color").val(event.color);
$('#modal').modal('show');
}
});
$("#button_ok").click(function (myevent) {
var my_input_time = $("#inp_time").val();
var momentTimeObj = moment(my_input_time, 'HH:mm:ss');
var momentTimeString = momentTimeObj.format('HH:mm:ss');
var my_input_date = $("#inp_hidden_date").val();
var momentDateObj = moment(my_input_date, 'YYYY-MM-DD');
var momentDateString = momentDateObj.format('YYYY-MM-DD');
var datetime = moment(momentDateString + ' ' + momentTimeString, "YYYY-MM-DD HH:mm");
var my_title = $("#inp_title").val();
var my_duration = $("#inp_duration").val();
var new_dur_time = moment.duration(my_duration).asHours();
//Add Decimal End Time to Start Time
var new_end_time = moment(datetime).add(new_dur_time, 'hours');
var new_information = $("#inp_information").val();
var new_color = $("#inp_color").val();
$.extend(curr_event, {
title: my_title,
start: datetime,
end: new_end_time,
information: new_information,
color: new_color
});
$("#calendar").fullCalendar('updateEvent', curr_event);
});
});
Hope this helps.
Greetings.

How do I get fullcalendar to display calendar on initial render?

When I initially load my calendar, it loads the calendar with all of the headings/buttons, but not the actual calendar itself. I have to press the "today" button for it to load the calendar on today's week. Any idea how to get it to do this on initial load? If it helps, here's the code I'm using. I'm pretty clueless as to what's happening here, I inherited this piece of work off someone else, this is my first time looking at this fullcalender addon.
function calendar() {
//gets saved events
var sourceFullView = { url: '/Calendar/GetDiaryEvents/' };
var sourceSummaryView = { url: '/Calendar/GetDiarySummary/' };
var CalLoading = true;
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView: 'agendaWeek',
editable: true,
allDaySlot: false,
selectable: true,
slotMinutes: 15,
events: '/Calendar/GetDiaryEvents/',
eventClick:
function(calEvent) {
//modal located at the bottom of the page
var modalElementId = $("#modal");
//url located in the Calendar controller. CalEvent Id referes to event id
var url = GetUrlPath() + '/Calendar/OpenDetailsModal?id=' + calEvent.id;
var appointmentId = calEvent.id;
//These are defined at the top of the page
$('#DiaryEventID').val(appointmentId);
$('#DiaryEventID').val("");
var viewModel = new CalenderViewModel(appointmentId);
showEditModal(null, viewModel, url, modalElementId);
$('.modal-backdrop').removeClass('modal-backdrop');
},
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
if (confirm("Confirm move?")) {
UpdateEvent(event.id, event.start);
} else {
revertFunc();
}
},
eventResize: function(event, dayDelta, minuteDelta, revertFunc) {
if (confirm("Confirm change appointment length?")) {
UpdateEvent(event.id, event.start, event.end);
} else {
revertFunc();
}
},
dayClick: function(date, allDay, jsEvent, view) {
$('#eventTitle').val("");
setTimeout(ShowClientEventModal(), 100);
for (i = 0; i < 2; i++) {
if (date != "") {
$('#eventClientDate').val($.fullCalendar.formatDate(date, 'dd/MM/yyyy'));
$('#eventClientTime').val($.fullCalendar.formatDate(date, 'HH:mm'));
$("#eventClientDate").datepicker({ dateFormat: 'dd/mm/yy' });
}
}
},
viewRender: function(view, element) {
if (!CalLoading) {
if (view.name == 'month') {
$('#calendar').fullCalendar('removeEventSource', sourceFullView);
$('#calendar').fullCalendar('removeEvents');
$('#calendar').fullCalendar('addEventSource', sourceSummaryView);
} else {
$('#calendar').fullCalendar('removeEventSource', sourceSummaryView);
$('#calendar').fullCalendar('removeEvents');
$('#calendar').fullCalendar('addEventSource', sourceFullView);
}
}
}
});
CalLoading = false;
}
Bit more info, this is strange, but when I press F12 on the browser to go into developer tools, then calendar suddenly renders as if I pressed the today button. But when I go into the calendar page with the debugger already open, it renders the headers without the calendar content. What the hell is going on?
I would suggest you try removing all code related to CalLoading, so remove the variable assignment from the top, remove the entire viewRender function, and remove the variable assignment to false at the bottom. It looks like some type of function for not displaying the events until they are all loaded, or something like that, and my guess is its not working properly.
Edit: It looks like the function swaps out event sources to sourceSummaryView on month view, and sourceFullView on any other, so removing this will still have the calendar default to the sourceFullView, but I do not know the difference of the two so you will just need to try and see how it works.
var CalLoading = true;
viewRender: function(view, element) {
if (!CalLoading) {
if (view.name == 'month') {
$('#calendar').fullCalendar('removeEventSource', sourceFullView);
$('#calendar').fullCalendar('removeEvents');
$('#calendar').fullCalendar('addEventSource', sourceSummaryView);
} else {
$('#calendar').fullCalendar('removeEventSource', sourceSummaryView);
$('#calendar').fullCalendar('removeEvents');
$('#calendar').fullCalendar('addEventSource', sourceFullView);
}
}
}
CalLoading = false;

Angular ui-calendar events function called twice

I am developing a project with AngularJS and using Angular-UI UI-Calendar. In my code I initialize eventSources model for ui-calendar to empty array ([]) and set ui-config "events parameter" to a custom function. That function makes an $http request and then calls the callback function given to the events function.
However, I found out that when I load the page or change the month viewed by left or right buttons, events function called twice. How can I solve that?
Here is my code:
function CalendarCtrl($scope, Data){
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
// Stores all events
var events = [];
/* config object */
$scope.uiConfig = {
calendar:{
height: 450,
editable: true,
header: {
left: 'prev,next',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
buttonText: {
month: "Ay",
week: "Hafta",
day: "Gün",
list: "Ajanda"
},
allDayText: "Tüm gün",
eventLimitText: "daha fazla",
firstDay: 1,
timeFormat: 'H:mm',
axisFormat: 'H:mm',
lazyFetching: true,
// Here listen for calendar change events
events: getEvents
}
};
// For angular ui-calendar element
$scope.eventSources = [];
// Calendar event handlers
function getEvents(from, to, callback){
console.log(from); // For test purposes
// Request for data from server and when it comes, call callback to update calendar
Data.calendar.get(moment(from).unix(), moment(to).unix()).then(function(events){
angular.forEach(events, function(event){
event.start = moment.unix(event.start);
if(event.end){
event.end = moment.unix(event.end);
}
else{
delete event.end;
}
var d = event.start;
if(d.hour() == 0 && d.minute() == 0 && d.second() == 0){
event.allDay = true;
}
if(event.important){
event.className = "important-event";
}
event.editable = true;
});
callback(events);
});
}
I have the solution.
Instead of registering an event handler to $scope.uiConfig.calendar.events, register that same function to $scope.eventSources array. Like that:
$scope.eventSources = [getEvents];
Whenever view changes and calendar needs data it will look at the $scope.eventSources elements. And if an element is a function it will be called and results will be shown in calendar.
We ran into a similar problem in a project and our solution was also in the eventSource initialization putting an empty object inside the array.
$scope.eventSources = [{}];

How to set full calendar to a specific start date and end date when it's initialized?

I would like to set the initial date and end date.
so when I call the function to display the calendar that will show only date between startdate and enddate.
Say for example the user selects a initial date 11-03-2014 and end date 17-03-2014 so what i went to display is it will display event of 12-03, 13-03,14-03,15-03,16-03.
I tried to call 'gotodate' display function but this doesn't seem to work.
You call 'gotodate' after initializing your calendar, and you move to the desired date.
Apart from that, in viewDisplay callback you set the min and max dates, and you disable the 'previews' and 'next' buttons when user reach the edges...
in the following example it allows navigation between today and 5 days in the future
viewDisplay: function(view) {
var today = new Date();
today = new Date ( today.getFullYear(), today.getMonth(), today.getDate() );
var maxDayLimit = new Date( new Date(today).setDate(today.getDate() + 5) );
if( view.end >= maxDayLimit ) {
$(".fc-button-next").addClass("fc-state-disabled");
}
else{
$(".fc-button-next").removeClass("fc-state-disabled");
}
if( view.start <= today ){
$(".fc-button-prev").addClass("fc-state-disabled");
}
else{
$(".fc-button-prev").removeClass("fc-state-disabled");
}
}
dynamic date:add this event in calendar function and this is dynamically pass date by function_name(_start_date,_end_date)
and starting from now viewRender Event:
viewRender: function (view) {
var moment1 = $('#calendar').fullCalendar('getDate');
var current_year = moment(moment1).format('YYYY-MM');
var start_year = moment(_start_date).format('YYYY-MM');
var end_month = moment(_end_date).format('YYYY-MM');
if (current_year >= end_month) {
$(".fc-next-button").addClass("fc-state-disabled");
bootbox.alert('Your Academic Session is over');
//alert('Your Academic Session is over');
}
else {
$(".fc-next-button").removeClass("fc-state-disabled");
}
if (current_year <= start_year) {
$(".fc-prev-button").addClass("fc-state-disabled");
bootbox.alert('Your Academic Session is over');
//alert('Your Academic Session is over');
}
else {
$(".fc-prev-button").removeClass("fc-state-disabled");
}
}

Categories

Resources