0

I have problem with my FullCalendar v6 and adding events to mysql database and refreshing page/events. If I add event, its correctly insert to database, but FullCalendar didnt load, and didnt display the event so I must push F5.

I have these code of FullCalendar:

document.addEventListener('DOMContentLoaded', function() {
  var calendarEl = document.getElementById('calendar');
  var calendar = new FullCalendar.Calendar(calendarEl, {
      locale: 'cs',
      editable: true,
      selectable: true,
      selectLongPressDelay: 500,
      unselectAuto: false,
      select: function(info) {

          var start = moment(info.start).format('YYYY-MM-DD HH:mm:ss');
          var end = moment(info.end).format('YYYY-MM-DD HH:mm:ss');

          $('#add-event-modal-visit #event_start').val(start);
          $('#add-event-modal-visit #event_end').val(end);

          $('#add-event-modal-visit').modal('show');

      },
      headerToolbar: {
          left: 'prev,next today',
          center: 'title',
          right: 'dayGridYear,dayGridMonth,timeGridWeek,timeGridDay'
      },
      views: {
          timeGridWeek: {
              titleFormat: {
                  year: 'numeric',
                  month: 'long',

              },
              dayHeaderFormat: { day: 'numeric', weekday: 'short' },
              slotLabelFormat: { hour: 'numeric', minute: 'numeric' },
          }
      },
      themeSystem: 'bootstrap5',

    firstDay: 1, 
    initialView: 'timeGridWeek', 
    nowIndicator: true, 
    slotMinTime: '08:00:00', 
    slotMaxTime: '21:00:00', 
    editable: true,
    selectable: true,
    dayMaxEvents: true, 
      eventContent: function(arg) {
          var startTime = calendar.formatDate(arg.event.start, {
              hour: '2-digit',
              minute: '2-digit'
          });
          var endTime = calendar.formatDate(arg.event.end, {
              hour: '2-digit',
              minute: '2-digit'
          });
          return { html: '<div class="fc-content">' +
          '<div class="fc-time">' + startTime + ' - ' + endTime + '</div>' +
          '<div class="fc-title"><b>' + arg.event.title + '</b></div>' +
          '<div class="fc-description">' + arg.event.extendedProps.description + '</div>' +
          '</div>' };
      },

      events: [
          <?php
         
          $query = "SELECT * FROM events ORDER BY id";
          $result = mysqli_query($conn, $query);

          while ($row = mysqli_fetch_array($result)) {
          $id = $row['id'];
          $title = $row['event_name'];
          $start = $row['event_start'];
          $end = $row['event_end'];
          $eventColor = $row['event_color'];
          $shortDescription = $row['event_short_description'];
          ?>
          {
              id: '<?php echo $id; ?>',
              title: '<?php echo $title; ?>',
              start: '<?php echo $start; ?>',
              end: '<?php echo $end; ?>',
              color: '<?php echo $eventColor; ?>',
              extendedProps: {
                  description: '<?php echo $shortDescription; ?>'
              }
          },
          <?php
          }
          ?>
      ],

  });

  calendar.render();
});

After click on time in FullCalendar, modal is show, where I fill data, after click on Done in modal window, I call function:

<script>

  
    $(document).ready(function() {
        $('#add-event-modal-visit #add_event_visit').on('click', function() {
            console.log("klik");
            var event_name = $("#add-event-modal-visit #event_name").val();
            var id_customer = $("#add-event-modal-visit #id_customer").val();
            var id_service = $("#add-event-modal-visit #id_service").val();
            var event_start = $("#add-event-modal-visit #event_start").val();
            var event_end = $("#add-event-modal-visit #event_end").val();
            var deposit = $("#add-event-modal-visit #deposit").val();
            var event_description = $("#add-event-modal-visit #event_description").val();
            var event_type = 'visit';

            console.log(event_name);
            console.log(id_customer);
            console.log(id_service);
            console.log(event_start);
            console.log(event_end);
            console.log(deposit);
            console.log(event_description);
            console.log(event_type);


            $.ajax({
                url: 'add_event/add_event_visit.php',
                data: 'event_name=' + event_name +
                '&id_customer=' + id_customer +
                '&id_service=' + id_service +
                '&event_start=' + event_start +
                '&event_end=' + event_end +
                '&deposit=' + deposit +
                '&event_description=' + event_description +
                '&event_type=' + event_type,
                type: "POST",
                success: function (json) {

                    console.log("ok");

    
                    $('#add-event-modal-visit').modal('hide');

                    //calendar.refetchEventsAndResources();
                    //calendar.render();
                    //calendar.refetchEvents();
                    //location.reload();
                },
                error: function () {
                    console.log("Chyba při ukládání události do databáze.");
                },
                dataType: 'json'
            });
        });
    });

</script>

Everything in console.log is write of correctly, after that ajax call php.script - add_event_visit.php with this code:

<?php

require('../../include/connection.php');

    $event_type = $_POST["event_type"];
    $event_name = $_POST["event_name"];
    $service_id = $_POST["id_service"];
    $customer_id = $_POST["id_customer"];
    $event_start = $_POST["event_start"];
    $event_end = $_POST["event_end"];
    $event_description = $_POST["event_description"];
    $deposit = $_POST["deposit"];

    $service_name = "
        select
        *
        FROM
            services
            where id = '$service_id';
        ";

    $mysql_query_service_name = mysqli_query($conn, $service_name);
    $row_service = mysqli_fetch_array($mysql_query_service_name);

    $event_short_description = $row_service['name'];

    $event_color = "
        select
        *
        FROM
            event_colors
            where id_item = '$service_id'
            and type = '$event_type';
        ";

    $mysql_query_event_color = mysqli_query($conn, $event_color);
    $row_event_color = mysqli_fetch_array($mysql_query_event_color);

    $event_color = $row_event_color['color'];

$sql = "INSERT INTO events(id, event_type, event_name, event_short_description, id_customer, id_service, event_start, event_end, event_color, event_description, deposit) 
VALUES (DEFAULT,'$event_type','$event_name','$event_short_description','$customer_id','$service_id','$event_start','$event_end','$event_color','$event_description','$deposit')";

if (mysqli_query($conn, $sql)) {
    $response = array('status' => 'success', 'message' => 'Data byla úspěšně aktualizována.');
} else {
    $response = array('status' => 'error', 'message' => 'Chyba při aktualizaci dat v databázi.');
}
header('Content-Type: application/json');
echo json_encode($response);

?>

The event is saved to database, but after close modal window, event wont show in FullCalendar, I must push F5 for refresh page. I tried: calendar.refetchEventsAndResources(); calendar.render();calendar.refetchEvents();. Everything not working. If i used location.reload() that reload page, so if I adding event for example with May date, that jumped back on actual week.

ADyson
  • 57,178
  • 14
  • 51
  • 63
Kubik Sukenik
  • 49
  • 1
  • 7
  • 3
    In your success handler for your ajax request you need to pass the newly added event to [Calendar::addEvent](https://fullcalendar.io/docs/Calendar-addEvent) – user1191247 Apr 19 '23 at 07:11
  • 1
    `refetchEvents()` doesn't work because you're not using a dynamic event source - fullCalendar doesn't know anywhere to fetch the events from! If you want that, implement the https://fullcalendar.io/docs/events-json-feed or https://fullcalendar.io/docs/events-function event feed patterns, instead of a static JS array. This would be advantageous anyway as time goes on, since it will only fetch data it actually _needs_ for the current view, rather than your entire history of events (which after a while of use, will be a large and slow to load). – ADyson Apr 19 '23 at 07:13
  • 1
    P.S. **Warning:** Your code is vulnerable to SQL Injection attacks. You should use parameterised queries and prepared statements to help prevent attackers from compromising your database by using malicious input values. http://bobby-tables.com gives an explanation of the risks, as well as some examples of how to write your queries safely using PHP / mysqli. **Never** insert unparameterised data directly into your SQL. The way your code is written now, someone could easily steal, incorrectly change, or even delete your data. – ADyson Apr 19 '23 at 07:14
  • 1
    https://phpdelusions.net/mysqli also contains good examples of writing safe SQL using mysqli. See also the [mysqli documentation](https://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php) and this: [How can I prevent SQL injection in PHP?](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) . Parameterising your queries will also greatly reduce the risk of accidental syntax errors as a result of un-escaped or incorrectly quoted input values. If you learnt your current technique from a tutorial or book, please don't use that resource again. – ADyson Apr 19 '23 at 07:15
  • Your two SELECTs can be easily combined into your INSERT query to avoid unnecessary round trips to the db server. – user1191247 Apr 19 '23 at 07:25
  • 1
    Actually, the two SELECTs should not even be necessary. They indicate that the data is denormalised. e.g. if event_short_description is always derived from service_id, then you don't need to store event_short_description in the events table at all...instead just store the service_id in events (as you're doing already), and use that as a foreign key to the services table - so when you are selecting events, you'd use a JOIN onto the services table to get the correct description. You avoid redundant and stale data that way. If you don't know what I mean, take a relational database design course. – ADyson Apr 19 '23 at 07:28
  • Thank you @ADyson for advices, regarding SQL, I will read the given links and modify the code. About FullCalendar, I changed the loading events by adding events: 'get_events.php', however if I add $('#calendar').fullCalendar('refetchEvents');, or calendar.refetchEvents();, in the success response of funciton, then I get an error - caught TypeError: $(...).fullCalendar is not a function, but I have the calendar loaded. – Kubik Sukenik Apr 19 '23 at 09:40
  • `$(...).fullCalendar is not a function`....well fullCalendar isn't a jQuery plugin (and hasn't been since v3). Your calendar object is `calendar` (as per `var calendar = new FullCalendar...`) so it would be `calendar.refetchEvents()` - that cannot cause the "$..". error. But as I said above, that won't work for you in this case anyway since you don't have a refreshable event source defined (according to what's in your question). `events: 'get_events.php'` will work _if_ that file returns event JSON, and nothing else - obviously I can't see what you've done there. – ADyson Apr 19 '23 at 09:49
  • Ok, I changed $('#calendar').fullCalendar('refetchEvents'); to calendar.refetchEvents(); but i still get error - caught TypeError: calendar.refetchEvents is not a function. In get_events.php I have that code and I think, that returns event JSON -`$sql = "SELECT * FROM events";$result =mysqli_query($conn, $sql);$events = array();while ($row = mysqli_fetch_assoc($result)) {$event = array('id' => $row['id'],'title' => $row['event_name'],'start' => $row['event_start'],'end' => $row['event_end']);array_push($events, $event); } echo json_encode($events);mysqli_close($conn);` events in cal. are show – Kubik Sukenik Apr 19 '23 at 11:20
  • 1
    That error is likely to be because `calendar` is out of [scope](https://www.google.com/search?q=js+variable+scope) when you are calling it. I guess you're using it in the `$(document).ready(function() {` block? I don't know why you have a separate `$(document).ready(function() {`? It's exactly equivalent to `document.addEventListener('DOMContentLoaded', function() {`. So everything that needs to occur after the page has loaded can all go inside one `document.addEventListener('DOMContentLoaded', function() {` block. Currently, your `calendar` variable is only in scope within that block. – ADyson Apr 19 '23 at 11:28
  • 1
    `I think, that returns event JSON`... you think? Or you know? Did you not test it independently before using it in fullCalendar? You can simply open that page in your browser and see what it returns. P.S. You still need to make it date-aware. FullCalendar will pass start and end dates to it (as per the docs) as query parameters, and you need to use those in your query to only return events which overlap those dates, so you don't unnecessarily download lots of historical/future events which the user might never look at. FC will automatically request more events if the calendar date changes. – ADyson Apr 19 '23 at 11:34
  • Thank you for advices, it works, problem was in with location of script, that was outside of `document.addEventListener('DOMContentLoaded', function() {` and thanks for json feeds and with SQL protection. – Kubik Sukenik Apr 20 '23 at 08:38

0 Answers0