Fullcalendar (v2.x) Getting day-cell from an eventClick? - javascript

I'm struggling to retrieve the day clicked when clicking on a multi-days (period) event (eventClick).
Whe clicking on the background cell, it's easy :
function dayClick(date, jsEvent, view) {
//todo: store related day
$scope.selectedDay = date;
}
But when clicking on an event (which is on a period of days), I can't retrieve which day exactly the user was on. (I need to perform a different action depending on the background day) :
function alertEventOnClick(event, jsEvent, view) {
// "event" stores only start and end date without any reference to the current day
// "jsEvent" retrieve the "td" element but fullcalendar HTML structure is complex and it's impossible to go-up to find the day-cell
// $scope.selectedDay = ??
};
I tried playing with "selectable" but "eventClick" JS Event doesn't propagate, and doesn't "select" the day
Thanks

If you don't need to catch event clicks at all, you can just add a class to all events with pointer-events: none;
JSFiddle Demo
eventRender: function (event, element) {
$(element).addClass('clickThrough');
},
IE8
Bleh. There is a hacky method to simulate pointer-events: none; on IE8 but while trying to implement it I found a simpler way to achieve the goal. (The simulated pointer-events hack is described here.)
To get the date at the cursor:
Hide the event table
Get element under cursor
Show the event table
JSFiddle Demo
eventClick: function (calEvent, jsEvent, view) {
var topLayer = $(jsEvent.currentTarget).closest("tbody");
topLayer.hide(); //hide the entire event layer (makes it work with multiple events)
var dayElement = document.elementFromPoint(jsEvent.pageX, jsEvent.pageY); //get the element under the cursor (should be a day cell)
topLayer.show();
alert($(dayElement).data("date"));
}
Better IE8 workaround
(this doesn't seem to work)
So it turns out that anchor tags have a better pointer-events: none; workaround. https://stackoverflow.com/a/18118092/728393
You simply add the attribute disabled="disabled" to the <a> and it can be clicked through.
JSFiddle Demo
eventRender: function (event, element) {
$(element).addClass('clickThrough').attr("disabled","disabled"); //disabled attribute is a IE workaround for pointer-events
},

So I finally found a quick(&dirty ?) solution relying on parsing close DOM Table elements.
From eventClick js event, I can retrieve the currentTarget clicked and go back in the table headers : the first row contains thead headers definition containing cell date mapping.
$scope.alertEventOnClick = function(event, jsEvent, view) {
var columnIndex = $(jsEvent.currentTarget).parent('td').get(0).cellIndex + 1;
var parentTable = $(jsEvent.currentTarget).closest('table');
var dateString = $('thead td:nth-child('+ columnIndex +')', parentTable).attr('data-date');
$scope.selectedDay = moment(dateString);
};
edit: solution OK for 1 event by day. but KO for more than one event by day ...
Another solution can be to determine x/y position of the clicked cell (by counting div/td childs) and map it with view.coordMap.grid.cellDates[position]

Here is my solution:
eventClick: function(event, jsEvent, view) {
var day=$(this).closest('.'+(view.type=='month'?'fc-row':'fc-time-grid')).find('.fc-bg td:eq('+$(this).closest('td').index()+')').data('date');
console.log(day);
}

Here is slicedtoad's solution modified to work with v4 of fullcalendar and also taking into account the window's current scroll position:
eventClick: function(ev) {
var topLayer = $(ev.el).closest(".fc-row");
var eventLayer = topLayer.find(".fc-content-skeleton");
eventLayer.hide();
var dayElement = $(document.elementFromPoint(ev.jsEvent.pageX - window.pageXOffset, ev.jsEvent.pageY - window.pageYOffset));
eventLayer.show();
var current_day = dayElement.attr("data-date");
console.log(current_day);
}

I updated Dane Iracleous's solution slightly to make it work with 1. click on multi-day events when there is more than one on the same day. and 2. this works in month/week/day views.
Using visibility/z-index solved my issue of the 'all day' container shrinking temporarily when the event layer was hidden.
getClickedDate(event) {
//used to get specific date clicked on multiple day event
let topLayer = $(event.el).closest(".fc-row");
let eventLayer = topLayer.find(".fc-content-skeleton");
let initialZIndex = $(eventLayer).css('z-index')
$(eventLayer).css({ 'visibility': 'hidden', 'z-index': '-1'});
let dayElement = $(document.elementFromPoint(event.jsEvent.pageX - window.pageXOffset, event.jsEvent.pageY - window.pageYOffset));
$(eventLayer).css({ 'visibility': 'visible', 'z-index': initialZIndex });
let clickedDate = dayElement.attr("data-date");
console.log('clicked date', clickedDate)
return clickedDate;
}

Related

Kendo ListBox: Return dropped items in order

I am using two listboxes, connected with each other, that allow drag and drop between the two. While using the reorder code found in another thread fixes the issue with reordering items within the same list, it doesn't address the issue when dragging and dropping an item from one listbox to the other. I understand that is because this isn't a "reorder" action, it is a "drop" action. I've tried many different angles, like using the "add" event, but there is no "offset" property in the (e) object.
How can I accomplish the same thing, that is, keep the dropped item in the order it is visually dropped?
Here is my widget function with the reorder event that properly orders the items as they are displayed in the listBox (why this doesn't happen automatically is beyond me!). Remember, the reorder event only occurs when moving items within the same listBox, not when dragging an item from one listBox to another.
$("#myMenus").kendoListBox({
draggable: true,
connectWith: "baseMenus",
dropSources: ["baseMenus"],
add: function(e) {
console.log('ADD');
console.log(e);
},
reorder: function(e) {
e.preventDefault();
var dataSource = e.sender.dataSource;
var dataItem = e.dataItems[0];
var index = dataSource.indexOf(dataItem) + e.offset;
dataSource.remove(dataItem);
dataSource.insert(index, dataItem);
},
});
I've managed to accomplish the same task, depending on the html hint that appears while dropping the item in the second listbox. I've modified your code with the solution.
$("#myMenus").kendoListBox({
draggable: true,
connectWith: "baseMenus",
dropSources: ["baseMenus"],
add: function(e) {
e.preventDefault();
var dataSource = e.sender.dataSource;
var dataItem = e.dataItems[0];
var index = $('li.k-drop-hint').index();
dataSource.insert(index, dataItem);
},
reorder: function(e) {
e.preventDefault();
var dataSource = e.sender.dataSource;
var dataItem = e.dataItems[0];
var index = dataSource.indexOf(dataItem) + e.offset;
dataSource.remove(dataItem);
dataSource.insert(index, dataItem);
},
});

Fullcalendar how to show html element in DayCell?

Hello i am trying to show html element in daycell but no success, but i am unable to show it next to calendar how can i show it in daycell? I am using 2.1.1 version
Javascript
dayClick: function(date, view ,calEvent, jsEvent) {
$(this).css('background-color', '#DDDDDD');
/*calEvent.start=moment(calEvent.start).format('YYYY/MM/DD hh:mm');
calEvent.end=moment(calEvent.end).format('YYYY/MM/DD hh:mm');*/
$('#myResults').html("10/5");
},
HTML
<div align="center" id="myResults" style="width:auto;height:auto;background:#AFEEEE;z-index:10001;font-size: 1em;"> </div>
Try eventRender callback, you can catch the rendering time of drawing events on the cells.
eventRender: function(event, element) {
// event means the event data you inserted.
// element means the DOM.
// standard event data has properties like this.
// event.title, event.start, ....
// and the element DOM has <span class='fc-title'></span> for 'event.title' string data.
// setting your html string to event.title doesn't help. It will show it as plain text.
var customHTML = '<div align="center" id="myResults" style="width:auto;height:auto;background:#AFEEEE;z-index:10001;font-size: 1em;"></div>';
$(element).find('.fc-title').html(customHTML);
}
This will work. I was going to produce this on JSFiddle but fullcalendar above v.2.1 requires a few more libraries and its predefined directory structure, I couldn't produce it properly.
Try give the code above as an option when you initialize fullcalendar.
This is working on load :D
dayRender: function(date, element, view){
var nDate = new Date();
if(date < nDate ) {
$(element).css("background", "#D1EEEE");
}
$(element).html("10/5").css('color', '#e50000');
},

jQuery UI Sortable containment unable to detect placeholder

So I was working on this application where I want people to be able to drag items from one table data to the other table data, which must be contained within the parent table row.
But whenever I drag it around it seems to stick to the containment excluding the height of any placeholders.
Try it yourself: http://jsfiddle.net/2wy8R/
Any idea of how I can make it select the parent of the parent? Of not, then, how can I make the placeholders count?
Greetings
.
Update: YouTube video of the problem http://youtu.be/PMXcQvJmRGw
OK, here you go. Overridden the default containment as it seems buggy with your scenario. Let me know if this is not a good idea but it seems to work:
http://jsfiddle.net/2wy8R/6/
$('#first, #second').sortable({
connectWith: '.sortable',
placeholder: 'placeholder',
start: function(event, ui) {
ui.placeholder.height(ui.item.height() - 4);
var p = $(ui.helper);
var tr = p.closest("tr");
$(document).mousemove(function(e) {
var pOffset = p.offset();
var trOffset = tr.offset();
if (pOffset.left < trOffset.left) {
p.css({left: trOffset.left});
}
if (pOffset.left + p.width() > trOffset.left + tr.width()) {
p.css({left: trOffset.left + tr.width() - p.width()});
}
if (pOffset.top < trOffset.top) {
p.css({top: trOffset.top});
}
if (pOffset.top + p.height() > trOffset.top + tr.height()) {
p.css({top: trOffset.top + tr.height() - p.height()});
}
});
}
}).disableSelection();
just be careful with it though, as this keeps adding mousemove events to the document. you may want to unbind mousemove before binding it...

change the color of a cell in a full calendar

I need to change the color of a cell of a arshaw full calendar.
My requirement is :There should be a same color for a td cell for list of holidays provided by a company.
There should be a same color for a td cell for list of holidays taken by an employee.
How we can achieve this.I am able to change the color of events but not the cell.
Also If we can change the color of a day inside a cell according to holidays and leave .
If you are using Jquery-Ui theme you need to remove ui-widget-content class and apply your own class. In the code below i'm using a 40x100 image with purple flat color.
CSS
.holiday
{
border:1px solid #69196c;
background: #764ead url(holiday.png) 50% top repeat-x;
color: white;
}
JS FULLCALENDAR
dayRender: function (date, cell) {
if ($.inArray(date, holidays) >= 0) {
// if you aren't using ui theme, just remove this line
$(cell).removeClass('ui-widget-content');
$(cell).addClass('holiday');
}
}
The cells in fullCalendar are table-cells - events are rendered as floating divs on top on these cells. So let's say in the month-view, each day-cell has a class associated with it. Like "fc-sun" for Sundays, "fc-mon" for Mondays and so on. Each cell also has the day-number class associated - like "fc-day1", "fc-day2".
So, let's say you want to change the background-color of all Sundays:
.fc-sun {
background-color: #FF0000;
color: #FFFFFF;
}
And so on. Hope this helps.
eventRender: function (event, element, monthView)
{
if (event.title == "HOLIDAY")
{
var one_day = 1000 * 60 * 60 * 24;
var _Diff = Math.ceil((event.start.getTime() - monthView.visStart.getTime())/(one_day));
var dayClass = ".fc-day" + _Diff;
$(dayClass).addClass('holiday-color');
}
}
Also, remember that you would need to clear these class names on month change or else they will stay the same background color for all the months.
Therefore, you might want/need to manage the navigation of the calendar manually using gotodate and then using jquery’s removeClass() selector to clear out the class names.
What you need to do is bind the click event of your fullcalendar's next and previous month buttons and do something like
$("#nextMonthBtn").click(function () {
// current year and month should be maintained, can be a`enter code here`enter code here`ccessed on loading attribute of the fullcalendar
//manually manage navigation`enter code here`
$('td').removeClass('holiday-color');
calRef.fullCalendar('gotoDate', _currentYear, _currentMonth, 1)
});
For aditional information please refer: http://vishaljadhav.net/coloring-certain-days-when-using-full-calendar/
Since they've updated fullcalendar I'm posting a new solution, I know few years passed from question but I guess is better late than never :)
eventRender: function(event, element, monthView) {
if (event.className == "holiday") {
var dateString = $.fullCalendar.formatDate(event.start, 'yyyy-MM-dd');
$('td[data-date="' + dateString + '"]').addClass('fully_colored_holiday');
}
}
and here is the class:
.fully_colored_holiday,
.fully_colored_holidaydiv,
.fully_colored_holidayspan{
background:#FF8C8C !important;
}

JQuery UI.sortable, how to change helper offset dynamically?

I have a list of items each with heavy content. When I apply jQuery sortable, what I wanted to achieve is this, when an item is dragged away and starts sorting, all the item contents will be hidden automatically.
From all my testtings, jQuery doesn't accommodate such changes very well, for example, if I do the following,
$("#sortable").sortable({
start: function(event, ui) {
$(".hidden").addClass("hide");
}
});
jQuery can't automatically figure out the sizes of hidden items and the sorting will be a mess.
So I solved it using an indirection, I firstly check mousedown, mouseup and mousemove event, and once dragging is detected (say when mousedown/mousemove for more than 50ms), I'll hide the items immediately.
And in jQuery, I used some delay to start sorting.
var mouse_down = false;
var mouse_down_time;
var content_hidden;
$(".drag-handle").bind("mousedown", function(e) {
mouse_down = true;
mouse_down_time = e.timeStamp;
$(".drag-handle").bind("mousemove", function(e) {
if (mouse_down && !content_hidden) {
if (e.timeStamp - mouse_down_time > 10) {
$(".hidden").addClass("hide");
content_hidden = true;
}
}
});
}).bind("mouseup", function(e){
$(".drag-handle").unbind("mousemove");
mouse_down = false;
if (content_hidden) {
$(".hidden").removeClass("hide");
content_hidden = false;
}
});
$("#sortable").sortable({
delay:100,
stop: function(event, ui) {
if (content_hidden) {
$(".hidden").removeClass("hide");
$(".drag-handle").unbind("mousemove");
content_hidden = false;
}
}
});
So jQuery will start sorting after item contents are hidden.
Everything works fine except the helper offset. The helper offset seems to bump up for exactly the amount of spaces occupied by the all the item contents above the dragged item (which are hidden now during dragging).
So my question is,
is there a way to dynamically calculate all the item heights before and after hidden, and set the helper offset accordingly?
Thanks.
Well, problem solved.
What I did is dynamically calculate all the items height above the dragged item (before and after hiding contents), and then set the helper offset to the corresponding value by setting css:({'top-margin':offset_value+'px'})

Categories