Fullcalendar with PHP and CodeIgniter - Modifying Events - Part 4

The final part of this tutorial series will see us implement a solution that allows us to modify events directly from the FullCalendar. We'll be using Bootstrap's modal solution again, so make sure to check out part 3 for a quick recap.

This tutorial is a continuation of our FullCalendar with PHP and CodeIgniter series. View previous parts:

We first must create another modal form for our edit event action. This form will be almost 100% similar to our Add Event modal, except we now need to give all out input fields an ID so we can identify them in the JavaScript code. We also need to change the form_open() URL to the edit_event method we'll be creating later on.

Modify application/views/calendar/index.php

<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Update Calendar Event</h4>
      </div>
      <div class="modal-body">
      <?php echo form_open(site_url("calendar/edit_event"), array("class" => "form-horizontal")) ?>
      <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Event Name</label>
                <div class="col-md-8 ui-front">
                    <input type="text" class="form-control" name="name" value="" id="name">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Description</label>
                <div class="col-md-8 ui-front">
                    <input type="text" class="form-control" name="description" id="description">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Start Date</label>
                <div class="col-md-8">
                    <input type="text" class="form-control" name="start_date" id="start_date">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">End Date</label>
                <div class="col-md-8">
                    <input type="text" class="form-control" name="end_date" id="end_date">
                </div>
        </div>
        <div class="form-group">
                    <label for="p-in" class="col-md-4 label-heading">Delete Event</label>
                    <div class="col-md-8">
                        <input type="checkbox" name="delete" value="1">
                    </div>
            </div>
            <input type="hidden" name="eventid" id="event_id" value="0" />
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <input type="submit" class="btn btn-primary" value="Update Event">
        <?php echo form_close() ?>
      </div>
    </div>
  </div>
</div>

Notice we also added in a new checkbox for deleting the event. There is also a hidden input form for storing the event ID (this is so we can identify which event is being modified). Make sure that the ID of the actual modal (#editModal) is not the same as your Add Event modal.

Next we need to modify our JavaScript code for FullCalendar to include a new event called EventClick. This event is fired when you click the name of any event on the calendar. When this happens, we need to get that event's data and populate our Edit Modal form with it.

Modify application/views/calendar/index.php

eventClick: function(event, jsEvent, view) {
          $('#name').val(event.title);
          $('#description').val(event.description);
          $('#start_date').val(moment(event.start).format('YYYY/MM/DD HH:mm'));
          if(event.end) {
            $('#end_date').val(moment(event.end).format('YYYY/MM/DD HH:mm'));
          } else {
            $('#end_date').val(moment(event.start).format('YYYY/MM/DD HH:mm'));
          }
          $('#event_id').val(event.id);
          $('#editModal').modal();
},

Notice how we apply the event data to our form using the #IDs we assigned to them in the Edit Form.

We use momentjs to format the date for our calendar. MomentJS uses a different format to that of PHP, but the above code should match the format we entered for our dates in the beginning of this tutorial. You can read more about MomentJS's format here: https://momentjs.com/

Finally, we make sure that our hidden field contains the event id so we know which event we are updating. Then we spring the modal into action using the modal() function.

Next we need to build our edit_event() function in our controller that will handle the form data.

Modify application/controllers/Calendar.php

public function edit_event()
     {
          $eventid = intval($this->input->post("eventid"));
          $event = $this->calendar_model->get_event($eventid);
          if($event->num_rows() == 0) {
               echo"Invalid Event";
               exit();
          }

          $event->row();

          /* Our calendar data */
          $name = $this->common->nohtml($this->input->post("name"));
          $desc = $this->common->nohtml($this->input->post("description"));
          $start_date = $this->common->nohtml($this->input->post("start_date"));
          $end_date = $this->common->nohtml($this->input->post("end_date"));
          $delete = intval($this->input->post("delete"));

          if(!$delete) {

               if(!empty($start_date)) {
                    $sd = DateTime::createFromFormat("Y/m/d H:i", $start_date);
                    $start_date = $sd->format('Y-m-d H:i:s');
                    $start_date_timestamp = $sd->getTimestamp();
               } else {
                    $start_date = date("Y-m-d H:i:s", time());
                    $start_date_timestamp = time();
               }

               if(!empty($end_date)) {
                    $ed = DateTime::createFromFormat("Y/m/d H:i", $end_date);
                    $end_date = $ed->format('Y-m-d H:i:s');
                    $end_date_timestamp = $ed->getTimestamp();
               } else {
                    $end_date = date("Y-m-d H:i:s", time());
                    $end_date_timestamp = time();
               }

               $this->calendar_model->update_event($eventid, array(
                    "title" => $name,
                    "description" => $desc,
                    "start" => $start_date,
                    "end" => $end_date,
                    )
               );

          } else {
               $this->calendar_model->delete_event($eventid);
          }

          redirect(site_url("calendar"));
     }

This code is very similar to our add_event function. Only first we need to validate the event we are modifying. We grab the hidden form field called event_id and then check to see if an event exists with that ID using the Calendar Model. Remember, we created these method's in part 2.

Once we've found it, we then get the form data about the event and run the same processes as before to validate the data. We update the event by calling update_event() and that concludes the edit_event() function.

Now you have a working edit function for your FullCalendar!

Tips for Improvement

I've used FullCalendar in a lot of my projects, so here are some tips to improve it:

  • Add in clickable elements. By default, when you click on the elements in FullCalendar, the cursor does not change to a pointer. You can modify this by using css: cursor: pointer. It just makes the UI feel more intuitive.
  • Implement datetimepicker. This JavaScript library will automatically allow you to select the date and time for the event using a helpful little "picker". Your users won't have to worry about formatting the date because the library does it automatically for you.
  • Colour code events. With FullCalendar, you can make each event appear a different colour- a good idea would be to group certain events with certain colours to help show related events.

I hope this series of tutorials helps you with implementing FullCalendar with PHP and CodeIgniter.

The full version of the files are below: application/controllers/Calendar.php

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Calendar extends CI_Controller 
{

    public function __construct() {
        Parent::__construct();
        $this->load->model("calendar_model");
    }

    public function index() 
    {
        $this->load->view("calendar/index.php", array());
    }

    public function get_events() 
    {
        // Our Stand and End Dates
        $start = $this->common->nohtml($this->input->get("start"));
        $end = $this->common->nohtml($this->input->get("end"));

        $startdt = new DateTime('now'); // setup a local datetime
        $startdt->setTimestamp($start); // Set the date based on timestamp
        $format = $startdt->format('Y-m-d H:i:s');

        $enddt = new DateTime('now'); // setup a local datetime
        $enddt->setTimestamp($end); // Set the date based on timestamp
        $format2 = $enddt->format('Y-m-d H:i:s');

        $events = $this->calendar_model->get_events($format, 
            $format2);

        $data_events = array();

        foreach($events->result() as $r) { 

            $data_events[] = array(
                "id" => $r->ID,
                "title" => $r->title,
                "description" => $r->description,
                "end" => $r->end,
                "start" => $r->start
            );
        }

        echo json_encode(array("events" => $data_events));
        exit();
    }

    public function add_event() 
    {
        /* Our calendar data */
        $name = $this->common->nohtml($this->input->post("name"));
        $desc = $this->common->nohtml($this->input->post("description"));
        $start_date = $this->common->nohtml($this->input->post("start_date"));
        $end_date = $this->common->nohtml($this->input->post("end_date"));

        if(!empty($start_date)) {
            $sd = DateTime::createFromFormat("Y/m/d H:i", $start_date);
            $start_date = $sd->format('Y-m-d H:i:s');
            $start_date_timestamp = $sd->getTimestamp();
        } else {
            $start_date = date("Y-m-d H:i:s", time());
            $start_date_timestamp = time();
        }

        if(!empty($end_date)) {
            $ed = DateTime::createFromFormat("Y/m/d H:i", $end_date);
            $end_date = $ed->format('Y-m-d H:i:s');
            $end_date_timestamp = $ed->getTimestamp();
        } else {
            $end_date = date("Y-m-d H:i:s", time());
            $end_date_timestamp = time();
        }

        $this->calendar_model->add_event(array(
            "title" => $name,
            "description" => $desc,
            "start" => $start_date,
            "end" => $end_date
            )
        );

        redirect(site_url("calendar"));
    }

    public function edit_event() 
    {
        $eventid = intval($this->input->post("eventid"));
        $event = $this->calendar_model->get_event($eventid);
        if($event->num_rows() == 0) {
            echo"Invalid Event";
            exit();
        }

        $event->row();

        /* Our calendar data */
        $name = $this->common->nohtml($this->input->post("name"));
        $desc = $this->common->nohtml($this->input->post("description"));
        $start_date = $this->common->nohtml($this->input->post("start_date"));
        $end_date = $this->common->nohtml($this->input->post("end_date"));
        $delete = intval($this->input->post("delete"));

        if(!$delete) {

            if(!empty($start_date)) {
                $sd = DateTime::createFromFormat("Y/m/d H:i", $start_date);
                $start_date = $sd->format('Y-m-d H:i:s');
                $start_date_timestamp = $sd->getTimestamp();
            } else {
                $start_date = date("Y-m-d H:i:s", time());
                $start_date_timestamp = time();
            }

            if(!empty($end_date)) {
                $ed = DateTime::createFromFormat("Y/m/d H:i", $end_date);
                $end_date = $ed->format('Y-m-d H:i:s');
                $end_date_timestamp = $ed->getTimestamp();
            } else {
                $end_date = date("Y-m-d H:i:s", time());
                $end_date_timestamp = time();
            }

            $this->calendar_model->update_event($eventid, array(
                "title" => $name,
                "description" => $desc,
                "start" => $start_date,
                "end" => $end_date,
                )
            );
            
        } else {
            $this->calendar_model->delete_event($eventid);
        }

        redirect(site_url("calendar"));
    }

}

?>

application/models/Calendar_model.php

<?php

class Calendar_Model extends CI_Model 
{

    public function get_events($start, $end) 
    {
        return $this->db
            ->where("start >=", $start)
            ->where("end <=", $end)
            ->get("calendar_events");
    }

    public function add_event($data) 
    {
        $this->db->insert("calendar_events", $data);
    }

    public function get_event($id) 
    {
        return $this->db->where("ID", $id)->get("calendar_events");
    }

    public function update_event($id, $data) 
    {
        $this->db->where("ID", $id)->update("calendar_events", $data);
    }

    public function delete_event($id) 
    {
        $this->db->where("ID", $id)->delete("calendar_events");
    }

}

?>

application/views/calendar/index.php

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Calendar Display</title>
        <link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

    
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

        <link rel="stylesheet" href="<?php echo base_url() ?>scripts/fullcalendar/fullcalendar.min.css" />
        <script src="<?php echo base_url() ?>scripts/fullcalendar/lib/moment.min.js"></script>
        <script src="<?php echo base_url() ?>scripts/fullcalendar/fullcalendar.min.js"></script>
        <script src="<?php echo base_url() ?>scripts/fullcalendar/gcal.js"></script>

        
    </head>
    <body>

    <div class="container">
    <div class="row">
    <div class="col-md-12">

    <h1>Calendar</h1>

    <div id="calendar">

    </div>

    </div>
    </div>
    </div>

    <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Add Calendar Event</h4>
      </div>
      <div class="modal-body">
      <?php echo form_open(site_url("calendar/add_event"), array("class" => "form-horizontal")) ?>
      <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Event Name</label>
                <div class="col-md-8 ui-front">
                    <input type="text" class="form-control" name="name" value="">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Description</label>
                <div class="col-md-8 ui-front">
                    <input type="text" class="form-control" name="description">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Start Date</label>
                <div class="col-md-8">
                    <input type="text" class="form-control" name="start_date">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">End Date</label>
                <div class="col-md-8">
                    <input type="text" class="form-control" name="end_date">
                </div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <input type="submit" class="btn btn-primary" value="Add Event">
        <?php echo form_close() ?>
      </div>
    </div>
  </div>
</div>

    <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Update Calendar Event</h4>
      </div>
      <div class="modal-body">
      <?php echo form_open(site_url("calendar/edit_event"), array("class" => "form-horizontal")) ?>
      <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Event Name</label>
                <div class="col-md-8 ui-front">
                    <input type="text" class="form-control" name="name" value="" id="name">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Description</label>
                <div class="col-md-8 ui-front">
                    <input type="text" class="form-control" name="description" id="description">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">Start Date</label>
                <div class="col-md-8">
                    <input type="text" class="form-control" name="start_date" id="start_date">
                </div>
        </div>
        <div class="form-group">
                <label for="p-in" class="col-md-4 label-heading">End Date</label>
                <div class="col-md-8">
                    <input type="text" class="form-control" name="end_date" id="end_date">
                </div>
        </div>
        <div class="form-group">
                    <label for="p-in" class="col-md-4 label-heading">Delete Event</label>
                    <div class="col-md-8">
                        <input type="checkbox" name="delete" value="1">
                    </div>
            </div>
            <input type="hidden" name="eventid" id="event_id" value="0" />
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <input type="submit" class="btn btn-primary" value="Update Event">
        <?php echo form_close() ?>
      </div>
    </div>
  </div>
</div>
    
<script type="text/javascript">
$(document).ready(function() {

    var date_last_clicked = null;

    $('#calendar').fullCalendar({
        eventSources: [
           {
           events: function(start, end, timezone, callback) {
                $.ajax({
                    url: '<?php echo base_url() ?>calendar/get_events',
                    dataType: 'json',
                    data: {
                        // our hypothetical feed requires UNIX timestamps
                        start: start.unix(),
                        end: end.unix()
                    },
                    success: function(msg) {
                        var events = msg.events;
                        callback(events);
                    }
                });
              }
            },
        ],
        dayClick: function(date, jsEvent, view) {
            date_last_clicked = $(this);
            $(this).css('background-color', '#bed7f3');
            $('#addModal').modal();
        },
       eventClick: function(event, jsEvent, view) {
          $('#name').val(event.title);
          $('#description').val(event.description);
          $('#start_date').val(moment(event.start).format('YYYY/MM/DD HH:mm'));
          if(event.end) {
            $('#end_date').val(moment(event.end).format('YYYY/MM/DD HH:mm'));
          } else {
            $('#end_date').val(moment(event.start).format('YYYY/MM/DD HH:mm'));
          }
          $('#event_id').val(event.id);
          $('#editModal').modal();
       },
    });
});
</script>
    </body>
</html>

Resources




Enjoyed that? Check These Posts Out

Learn Linux: Setup DNS Server with Bind On Debian

Using Datatables with CodeIgniter Tutorial

Pro Login User Management System - PHP

Setup the new Envato API to check Product Codes with PHP

Article Comments

Let us know your thoughts below by adding a quick comment!

14/06/2017

Simon

Thanks for the tutorial. It is hard to find anything that provides the level of detail you have done on how to integrate all the key features of fullcalendar and PHP.

Reply

14/06/2017

Phil Baines

Thank you so much for this tutorial!! Just a few fixes though, there are a entries in the Calender.php which need correction ie $start_date = $sd->format('Y-m-d H:i:s') should have double quotations instead of single ones so the correct line would be $start_date = $sd->format("Y-m-d H:i:s")


Also for the Edit_Event the calender data has nohtml which gave me an error, i reverted to what the layout was for the Add_Event
$name = $this->input->post("name");
$desc = $this->input->post("description");
$start_date = $this->input->post("start_date");
$end_date = $this->input->post("end_date");
$delete = intval( $this->input->post("delete"));

Reply

15/06/2017

Alex

Hey thanls you so much for your tutoriel. it's very detail and nice explain.
Just i can't make new event cause codeigniter said Fatal error: Call to a member function format() on boolean in D:\wamp64\www\schepmans\application\controllers\Cal.php on line 59

if(!empty($start_date)) {
$sd = DateTime::createFromFormat('Y/m/d H:i', $start_date);
$start_date = $sd->format("Y-m-d H:i:s"); =====>> this line
$start_date_timestamp = $sd->getTimestamp();

Could you help me please.

Reply

15/06/2017

Patchesoft

@Alex are you making sure your date form for $start_date is correct? The DateTime::createFromFormat() is probably returning false so it can't create the date object.

Reply

Leave A Comment