15
votes

In fullcalendar you can select an event (which triggers) the eventClick function/callback. What I would like to do is highlight the day of the event when the event is clicked (in month view).

For example, if the event is on October 30 and I select the event I would like the background color of the day to be highlighted. This is very similar to how fullcalendar handles "today" where it highlights today in a yellowish color.

I can't seem to figure out how to tie the fc-event class or the event object itself to the actual day div in the calendar. My October 30th event appears within the following div (which is the October 30 box):

<div class="fc-sun fc-widget-content fc-day35 fc-first">

How can I find this div (so that I can highlight it) based on the event object?

9

9 Answers

10
votes

Sorry this is a rough solution, mostly from memory, as I'm not set up with any dev tools at this computer.

Hopefully this is what you're looking for!

//create fullCalendar:
$("#calendar").fullCalendar({
    /* options */

    eventClick: function(event, jsEvent){
        //use the passed-in javascript event to get a jQuery-wrapped reference
        //to the DOM element we clicked on.
        //i can never remember if this is .target, .currentTarget, or .originalTarget
        //... jquery has spoiled me
        var $clickedEvent = $(jsEvent.target);

        //tell the "selectionManager" to find the day this event belongs to,
        //and add the "selected" css class to it
        selectionManager.select($clickedEvent);
    }
});

//define an object that handles the adding-removing of the 'selectedDay' css class
var selectionManager = (function(){
    //i like making private variables :-)
    var $curSelectedDay = null

    //define a "select" method for switching 'selected' state
    return {
        select: function($newEvent) {
            if ($curSelectedDay){
                //if we already had a day chosen, let's get rid of its CSS 'selectedDay' class
                $curSelectedDay.removeClass("selectedDay");
            }
            //find the parent div that has a class matching the pattern 'fc-day', and add the "selectedDay" class to it
            $curSelectedDay = $thisEvent.closest('div[class~="fc-day"]').addClass("selectedDay");
        }       
    };
})();
13
votes

You can simply use the select method in full calendar.

For example:

$('#calendar').fullCalendar('select', date);

Where date comes from event.start:

eventClick: function( event, jsEvent, view ) {
    //pass event.start to select method
}
4
votes

Here's a slightly simpler solution that worked for me:

$(".fc-state-highlight").removeClass("fc-state-highlight");
$(jsEvent.currentTarget).addClass("fc-state-highlight");

...that goes inside of your click handler, like:

$('#eventCalendar').fullCalendar({
    dayClick: function(date, allDay, jsEvent, view) {
        $(".fc-state-highlight").removeClass("fc-state-highlight");
        $(jsEvent.currentTarget).addClass("fc-state-highlight");

    }
});

Note that this is using the dayClick handler instead of the eventClick handler. I don't see why it should not work with eventClick as well, but I have not tested that yet.

Edit:

Using a comparable approach for the eventClick handler proved to be more complicated than I thought it would be. The problem is that, in terms of DOM hierarchy, there is no parent/child relationship between the containing td element for a 'day' and the containing div elements for the events that are shows as occurring on that day.

So I had to write a function to lookup the correct td element for a given date. I ended up with something like:

function findContainerForDate(date) {
    var firstDayFound = false;
    var lastDayFound = false;
    var calDate = $('#eventCalendar').fullCalendar('getDate');

    var allDates = $('td[class*="fc-day"]')
    for (var index = 0; index < allDates.length; index++) {
        var container = allDates[index];
        var month = calDate.getMonth();
        var dayNumber = $(container).find(".fc-day-number").html();
        if (dayNumber == 1 && ! firstDayFound) {
            firstDayFound = true;
        }
        else if (dayNumber == 1) {
            lastDayFound = true;
        }

        if (! firstDayFound) {
            month--;
        }
        if (lastDayFound) {
            month++;
        }

        if (month == date.getMonth() && dayNumber == date.getDate()) {
            return container;
        }
    }
}

...and then I could implement eventClick like this:

eventClick: function(calEvent, jsEvent, view) {
    var selectedContainer = findContainerForDate(calEvent.start);

    $(".fc-state-highlight").removeClass("fc-state-highlight");
    $(selectedContainer).addClass("fc-state-highlight");
}
4
votes
eventRender: function (event, element, view) {          
        // like that
        var dateString = $.fullCalendar.formatDate(event.start, 'yyyy-MM-dd');
        view.element.find('.fc-day[data-date="' + dateString + '"]').css('background-color', '#FAA732');

        // or that
        var cell = view.dateToCell(event.start);
        view.element.find('tr:eq(' + (cell.row + 1) + ') td:eq(' + cell.col + ')').css('background-color', '#FAA732');
    }

Is there better solution?

0
votes

My take on aroth's finder function

     // based on the given event date return the full calendar day jquery object (<td ...>)
     // matching day and month
     //
     // assumptions:
     //  - the event date is if for the same year as the current viewable month
     //  - the fc-day* TD's are in chronological order
     //  - the fc-day* TD's not for the current month have a class of fc-other-month
     //
    findFullCalendarDayForClickedEvent : function( eventDate ) {

        var foundDay;

        var $theCalendar = $( '#myCalendar' );

        var currentDate = $theCalendar.fullCalendar( 'getDate' );
        var fullCalendarDayContainers = $theCalendar.find( 'td[class*="fc-day"]' );

        for( var i = 0; i < fullCalendarDayContainers.length; i++ ) {

            var $currentContainer = $( fullCalendarDayContainers[ i ] );

            var dayNumber = $currentContainer.find( '.fc-day-number' ).html();

            // first find the matching day
            if ( eventDate.getDate() == dayNumber ) {

                // now month check, if our current container has fc-other-month
                // then the event month and the current month needs to mismatch,
                // otherwise container is missing fc-other-month then the event
                // month and current month need to match
                if( $currentContainer.hasClass( 'fc-other-month' ) ) {

                    if( eventDate.getMonth() != currentDate.getMonth() ) {
                        foundDay = $currentContainer;
                        break;
                    }
                }
                else {
                    if ( eventDate.getMonth() == currentDate.getMonth() ) {
                        foundDay = $currentContainer;
                        break;
                    }
                }
            }
        }

        return foundDay;
    }
0
votes

Thanks to Fitz Agard's answer for the existence of fullcalendar select method, here's a version that works even for multiple days events.

Basically it tries to find the day the mouse click coordinates are within, then it passes its date to the fullcalendar select method.

function findClickedDay(e) {
 var days = $('#calendar .fc-day');
  for(var i = 0 ; i < days.length ; i++) {
      var day = $(days[i]);
      var mouseX = e.pageX;
      var mouseY = e.pageY;
      var offset = day.offset();
      var width  = day.width();
      var height = day.height();

      if (    mouseX > offset.left && mouseX < offset.left+width 
           && mouseY > offset.top  && mouseY < offset.top+height )
         return day;
  }
}

function myDayClick(date) { ... } // Optional

$('#calendar').fullCalendar({
  dayClick: function(date) { myDayClick(date); }, // Optional
  eventClick: function(event, jsEvent, view) {
    clickedDay = findClickedDay(jsEvent);
    var date = new Date(clickedDay.data('date'));
    $('#calendar').fullCalendar('select', date);
    myDayClick(date); // Optional
  }
});

EDIT:

I just realized fullCalendar select method does not trigger the dayClick callback. So if you have set a dayClick callback you must wrap it in a function (called myDayClick here) and call it in the eventClick callback. If you don't have a dayClick callback then you can remove the Optional parts.

0
votes

Not sure if this helps but I've found that this works quite nicely, similar to kayz1's solution...

            $("[data-date='" + $.datepicker.formatDate('yy-mm-dd', new Date(calEvent.start)) + "']").addClass("fc-state-highlight");
0
votes

So many answers. Little investigations give me more clear code: fullcalendar v2.1.1

 onDayClick = function( date, jsEvent, view ){
    var cell = view.dateToCell(date);
    var el = view.dayGrid.getCellDayEl(cell);
    var $clickedEvent = $(el);
    $clickedEvent.addClass("SelectedDay");
};
-1
votes

If you upgrade to fullcalendar v2 or greater it is very simple:

$('#calendar').fullCalendar({
    eventClick: function(calEvent, jsEvent, view) {
        // change the border color just for fun
        $(this).css('border-color', 'red');
    }
});

Here is the link for eventClick.