user3463807 user3463807 - 2 months ago 67
HTML Question

Full Calendar double events if i change to month

i have a full calendar script with the default view on agendaWeek. For some reason when i change to month it calls the get-events again and i don't know why, that doubles my events. Here is my script. I don't see in my cod calling the calendar again if i change the view. When i submit the form to store the events in database i call the events again to see them on calendar without refreshing and if i press on month after it calls get-events again, that causing my double events. How can i stop getting events again when i change to month view?

<script>

$( "body" ).on('change','#trotineta',function() {

var trotineta=$( "#trotineta" ).val();
var url='php/get-events.php?trotineta='+ trotineta;



$('#calendar').fullCalendar(
{
defaultView: 'agendaWeek',
header:
{
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultDate: new Date(),
selectable: true,
selectHelper: true,
selectOverlap: false,
select: function(start, end, view) {
var vedere=$('#calendar').fullCalendar( 'getView' );
if(vedere.name=='agendaDay' || vedere.name=='agendaWeek')
{
$('#basicModal').modal('show');
}
$('#plecare').text(moment(start).format("DD-MM-YYYY HH:mm"));
$('#retur').text(moment(end).format("DD-MM-YYYY HH:mm"));

$('#start_date').val(moment(start).format("Y-MM-DD HH:mm"));
$('#end_date').val(moment(end).format("Y-MM-DD HH:mm"));
},
editable: false,
eventStartEditable: false,
eventLimit: true, // allow "more" link when too many events

dayClick: function(date, jsEvent, view) {

//alert('Clicked on: ' + date.format());
//alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
//alert('Current view: ' + view.name);
if (view.name != 'month')
return;

if (view.name == 'month') {
$('#calendar').fullCalendar('changeView', 'agendaDay');
$('#calendar').fullCalendar('gotoDate', date);
}

},

eventRender: function(event, element) {

element.find('.fc-title').attr("data-id",event.id);

},

timeFormat: 'H:mm' ,
axisFormat: 'H:mm',


loading: function(bool)
{
$('#loading').toggle(bool);
}

});

$("#calendar").fullCalendar('removeEvents');
$("#calendar").fullCalendar('addEventSource', url);

});
</script>

<script>

$("body").on("submit","form#confirm", function(e){
e.preventDefault();
var trotineta=$( "#trotineta" ).val();
var url_event='php/get-events.php?trotineta='+ trotineta;

$.ajax({
type: "POST",
url: "app/add_rezervare.php?id_trotineta=" + trotineta,
data: $("form#confirm").serialize(),
success: function(data){

$("#calendar").fullCalendar('removeEvents');
$("#calendar").fullCalendar('addEventSource', url_event);
$('#basicModal').modal('hide');
}


});
return false;
});


</script>

Answer Source

You're going about this all the wrong way. There's no need to keep adding/removing event sources, and there's no need to keep re-initialising the calendar on every "change" event. It's all very inefficient, and also is ultimately the root of your problem.

Your main flaw is these lines:

$("#calendar").fullCalendar('removeEvents'); 
$("#calendar").fullCalendar('addEventSource', url);

These methods are not opposites.

removeEvents removes events from the calendar, but it does not remove the source of those events (i.e. the URL which fullCalendar keeps a record of, to know where to fetch them from again in future). However addEventSource adds another URL to the list of URLs which fullCalendar stores. When it fetches events, it fetches events from all the stored URLs. Every time you run addEventSource, you add another source of events. However, as discussed above, you are never removing them, so they just keep building up.

As soon as you add two identical URLs as two different event sources, you will start to see duplicate events, because there are two eventSources listed in fullCalendar with the same URL.

You said "For some reason when i change to month it calls the get-events again and I don't know why". This is the default behaviour. fullCalendar tries to be efficient and only fetch events from the server which it actually needs - i.e. only the events for the current view. It sends two date parameters "start" and "end" to your server and expects that the server will read these and use them to filter the list of events it returns. Then if the view or date range changes, it will run a new request to the server with different date parameters, to fetch events for that date range (unless it has already cached them from an earlier request).

This is usually more efficient, because there's a chance the user might never change the view, and also if you have many years worth of events, they will take a long time to download all in one go, and most will never be looked at by the user.

Anyway, there's really no need to make your code as complicated as you have. You can use the "events-as-a-function" feature to mean you need only add one event source, when the calendar is first created, and use that to pass any changes in the trotineta value to the server when re-fetching events. When the value of trotineta changes, you just tell fullCalendar to refetch the events using the new value. fullCalendar will take care of the rest. See https://fullcalendar.io/docs/event_data/events_function/.

Here's an example:

$(function() {
  $('#calendar').fullCalendar({
    defaultView: 'agendaWeek',
    header: {
      left: 'prev,next today',
      center: 'title',
      right: 'month,agendaWeek,agendaDay'
    },
    defaultDate: new Date(),
    selectable: true,
    selectHelper: true,
    selectOverlap: false,
    select: function(start, end, view) {
      var vedere = $('#calendar').fullCalendar('getView');
      if (vedere.name == 'agendaDay' || vedere.name == 'agendaWeek') {
        $('#basicModal').modal('show');
      }
      $('#plecare').text(moment(start).format("DD-MM-YYYY HH:mm"));
      $('#retur').text(moment(end).format("DD-MM-YYYY HH:mm"));

      $('#start_date').val(moment(start).format("Y-MM-DD HH:mm"));
      $('#end_date').val(moment(end).format("Y-MM-DD HH:mm"));
    },
    editable: false,
    eventStartEditable: false,
    eventLimit: true, // allow "more" link when too many events

    dayClick: function(date, jsEvent, view) {

      //alert('Clicked on: ' + date.format());
      //alert('Coordinates: ' + jsEvent.pageX + ',' + jsEvent.pageY);
      //alert('Current view: ' + view.name);
      if (view.name != 'month')
        return;

      if (view.name == 'month') {
        $('#calendar').fullCalendar('changeView', 'agendaDay');
        $('#calendar').fullCalendar('gotoDate', date);
      }

    },
    eventRender: function(event, element) {
      element.find('.fc-title').attr("data-id", event.id);
    },
    timeFormat: 'H:mm',
    axisFormat: 'H:mm',
    loading: function(bool) {
      $('#loading').toggle(bool);
    },
    events: function(start, end, timezone, callback) { //events-as-a-function
      $.ajax({
        type: "GET",
        url: 'php/get-events.php',
        dataType: "json",
        data: {
          "trotineta": $("#trotineta").val(), //dynamically gets the current value of trotineta each time a request is made
          "start": start.format("YYYY-MM-DD"), //pass start and end dates to your server to allow filtering by date
          "end": end.format("YYYY-MM-DD")
        },
        success: function(data) {
          callback(data); //return the event data to fullCalendar
        }
      });
    }
  });

  $("body").on('change', '#trotineta', function() {
    $("#calendar").fullCalendar("refetchEvents"); //tell fullCalendar to refresh the events. It will grab the new value of trotineta automatically (see the events function)
  });

  $("body").on("submit", "form#confirm", function(e) {
    e.preventDefault();
    var trotineta = $("#trotineta").val();

    $.ajax({
      type: "POST",
      url: "app/add_rezervare.php?id_trotineta=" + trotineta,
      data: $("form#confirm").serialize(),
      success: function(data) {

        $("#calendar").fullCalendar('refetchEvents'); //again just tell fullCalendar to refresh. It will take care of the rest.
        $('#basicModal').modal('hide');
      }

    });
  });
});