Couple

In the previous part of this series we saw how to add fullCalendar events via CakePHP to a MySQL events table. In this post I’ll focus on editing the events that Fullcalendar displays.

To provide a complete calendar solution on your CakePHP website, you’d need to let your users move events around, change their details (e.g. location) and even delete them if they are cancelled. Using Fullcalendar and the integration in this post – you’ll be able to do all this in a snap.

So, fullCalendar exposes a few event handles for you.

  • dayClick: function(date, allDay, jsEvent, view) This is the one used for adding events, which I covered in the previous post
  • eventClick: function(calEvent, jsEvent, view) We use this to edit an event’s details
  • eventDrop: function(event,dayDelta,minuteDelta,allDay,revertFunc)
  • eventResize: function(event,dayDelta,minuteDelta,revertFunc)

I’ll cover eventDrop and eventResize in future posts. In this one – let’s dig into eventClick.

EventClick

The eventClick event is fired when the user clicks an event displayed on FullCalendar’s view (a different event, dayClick, is fired when an empty slot is clicked).
To capture this event you’ll need to define an event handler like this:

    $(document).ready(function() {
        ...
        $('#calendar').fullCalendar({
            ...
            eventClick: function(calEvent, jsEvent, view) {
                $("#eventdata").show();
                $("#eventdata").load("<?php echo Dispatcher::baseUrl();?>/events/edit/"+calEvent.id);
            },
            ...

The first thing that happens in this event handler is that the <div> element containing the event data is shown (See the previous post in the series for this div’s discussion). Then we fire an ajax request to the events_controller to load the div’s content.

The ajax request calls the edit method with the id of the event that the user clicked. The edit method in events_controller loads the event data like so:

<?php
//events_controller.php
function edit ($id=null) {
    if (empty($this->data)) {
        if ($id==null) {
            //fail gracefully in case of error
            return;
        }
        $ev = $this->Event->findById($id);
        $ev['Event']['start']=date('Y-m-d h:i:s',strtotime($ev['Event']['start']));
        $ev['Event']['end']=date('Y-m-d h:i:s',strtotime($ev['Event']['end']));
        $this->set("event",$ev);
        if ($ev['Event']['allday']=='1') {
            $displayTime = 'All day event';
        } else {
            $displayTime = date('D M d, H:i',strtotime($ev['Event']['start'])) . '&mdash;' . date('H:i',strtotime($ev['Event']['end']));
        }
        $this->set('displayTime',$displayTime);
        $this->layout="empty";
    } else {
        $this->Event->id = $this->data['Event']['id'];
        $this->Event->saveField('title',$this->data['Event']['title']);
        $this->redirect(array('controller' => "events", 'action' => "calendar",substr($this->data['Event']['start'],0,4),
            substr($this->data['Event']['start'],5,2),substr($this->data['Event']['start'],8,2)));
    }
}
?>

In the spirit of Cake, this method handles both the load of the data to edit and its save.
If no event is loaded (hence – this is the load() ajax call when the eventClick event is fired) – the method loads the event from the database, and created displayTime (a nice representation of the event’s start and end time, to display to the user). Note that the layout is set to empty – because the method is only supposed to populate the event data <div> and not the entire page.

The second part of the method is for the form-submit option. Let’s deal with the view first, and the function of this part will be mostly self-explantory.

When the edit method is called for the first time, it populates data to display on the event data <div>. Cake will then respond with the edit.ctp view – which the div will display.

<?php
    echo $form->create('Event', array('target'=> '_parent') );
    echo $form->input('id',array('type'=>'hidden','value'=>$event['Event']['id']));
    echo $form->input('title' , array('value'=>$event['Event']['title']));
    echo 'When: ' .$displayTime; ?>
    <a href="<?php echo Dispatcher::baseUrl();?>/events/delete/<?php echo $event['Event']['id'];?>" onClick="return confirm('Do you really want to delete this event?');">Delete</a>
    <?php echo $form->end(array('label'=>'Save' ));
    //Below is just a cancel button. See previous post for the back() function ?>
    <input class="nicebutton" type="button" value="Cancel" onClick="back();">

Notice that the view only lets the user edit the event title – but it is easy enough to let the user edit other fields.
We also let the user delete the event if they want.

Below is the event data div element, populated with the event’s data after the event was clicked and the eventClick event was fired.

Event Data Div - edit mode

In this <div> you may change the event title. When you click Save, the edit method is called again. This time, $this->data is not empty, so the method will update the event with the new title:

$this->Event->id = $this->data['Event']['id'];
$this->Event->saveField('title',$this->data['Event']['title']);

It will then redirect to the main calendar page (calendar.ctp) with the event’s start date as the view parameters:

$this->redirect(array('controller' => "events", 'action' => "calendar",substr($this->data['Event']['start'],0,4),
    substr($this->data['Event']['start'],5,2),substr($this->data['Event']['start'],8,2)));

The reason we supply the date to the calendar view has to do with defaults. If fullCalendar is initialised without a specified date, it defaults to display a date range containing the current date. E.g. – if fullCalendar is configured to display a week-view – it will default to the week containing today’s date.

The event the user just edited may be some weeks in the future, and it’s bad user-experience to let someone edit an event and then throw them off to a completely different time-slot. Hence, the calendar method in events_controller receives a date as a request parameter, and ensures that fullCalendar displays the date range containing this date.

function calendar($year=null,$month=null,$day=null) {
    if ($year!=null) {
        $this->set('openYear',$year);
        if ($month!=null) {
            $month = ltrim($month,'0');
            $month = $month-1;
            $this->set('openMonth',$month);
        }
        if ($day!=null){
            $day = ltrim($day,'0');
            $this->set('openDay',$day);
        }
    }
}

and in the view:

    $(document).ready(function() {
        $('#calendar').fullCalendar({
        ...
        <?php if (isset($openYear)) { ?>
            year: <?php echo $openYear.',';
        }?>
        <?php if (isset($oMonth)) { ?>
            month: <?php echo $openMonth.',';
        }?>
        <?php if (isset($oDay)) { ?>
            date: <?php echo $openDay.',';
        } ?>
        ...

The fullCalendar and CakePHP Series:

  1. Part 1: Set up
  2. Part 2: Creating an event source
  3. Part 3: Adding events
  4. Part 4: Editing events
  5. Part 5: Dragging and resizing

Popularity: 55% [?]

Tagged with:
 

11 Responses to FullCalendar and CakePHP part 4 – Editing Events

  1. Andres says:

    Great series about the calendar, thanks a lot I have my calendar working now… I was having problems to make it work but I realized that the id parameter wasn’t being sent to the edit method, I added a hidden field for event ID and it made it happen.

    echo $form->input(‘id’, array(‘type’=>’hidden’,'value’=>$event['Event']['id']));

    Thanks a lot.

  2. Duck Ranger says:

    @Andres – you’re absolutely right… I missed this in copy and paste :( I corrected the tutorial now. Thanks a lot!

  3. Niels says:

    Hi,
    This tutorial is great! I used it to build up a nice and clean example from scratch, see http://www.sokati.com/main/openSource . I’ve put it there because you can not find a out-of-the-box working copy of fullcalendar anywhere. Anyway, it might be usefull for people reading this article!
    Thanks again!
    Niels

  4. Matt says:

    Hi Duck Ranger, I’m just coming to look at making some tweaks and was hoping you might be able to give a little more advice. Could you explain how the delete link is suppose to work? for me, clicking the link goes to http://localhost:8888/events/delete/79 with the error:

    Error: The requested address ‘/events/delete/79′ was not found on this server.

    is there something missing, that i need to do to get the delete link working?

  5. Duck Ranger says:

    @Matt – if you get this error, it means that either the events_controller is not found, or the delete action inside it is not found.

    Ensure that you have them both.
    The delete action should just delete the Event from the underlying database.

    Cheers

  6. Matt says:

    @Duck Ranger – Excellent thanks, it seems to be finding the delete action within my event_controller but doesnt seem to be deleting the event :( did you have an example of the delete function you could share?

  7. Duck Ranger says:

    @Matt – to delete a record with CakePHP use the Model’s delete action:

    function delete ($id) {
        $this->Event->delete($id);
    }

    If you follow this tutorial, there’s no delete view, and you need to return the user to the original view, so you will probably want to add a redirect at the end of the method.

    Cheers.

  8. Matt says:

    @Duck Ranger – Brilliant! As always you are a star. Thanks.

  9. Jason says:

    Hi, is it possible to extend fullcalendar with extra field like name, location etc?

    Tnx

  10. Duck Ranger says:

    @Jason – Fullcalendar itself may be extended, but to do this – you’ll need to go into the javascript code itself, and if you change that – you’ll need to ensure your changes are still valid when you upgrade.

    If you need something like this, I suggest you do it on the ‘using’ code. For example – on the Cake side of thing.
    Cheers,

  11. [...] a form it’s currently possible to edit and create events, but not directly from the calendar. At http://duckranger.com/2010/04/fullcalendar-and-cakephp-part-4-editing-events/ they have added these functions, but this is for CakePHP. So I guess what I’m asking is how would [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Set your Twitter account name in your settings to use the TwitterBar Section.