If an event start on a date and ends on some other date (say, next date). I want to show such events in allDay slot but don't want to mark event.allDay = true;
Any idea how can I do this ?
I modified the calendar code like this:
Find this method (for me it's on line#4467)
function renderEvents(events, modifiedEventId)
In this method find the following check:
if (events[i].allDay) { ... }
Replace it with this:
if (events[i].allDay || (events[i].end - events[i].start > 3600000) ) {
// if event spans more than a day show it in allDay area
...
}
Now any events that span more than a day will be shown in allDay area even if they are not marked 'allDay'
This was my requirement I had to do it like this. I mentioned it here in case anyone else come here searching a similar solution.
Related
I am using the eventContent hook in FullCalendar to send back JSX so that my events are customized in the calendar. Works great. However, I'd like to format them differently based on if the events are single day or multi day. In the default view, single day events have a colored dot and multi day events have a colored bar.
The arg that gets passed into the eventContent hook has things like isStart, isEnd, etc., but nothing about isSingleDay or whatever.
Is there an attribute in the arg somewhere that has this info and I'm just not seeing it, or do I simply need to just check start and end and calculate myself if the event is single day or multi day?
For now, I ended up just using moment.js, since I was already using the moment plugin for FullCallendar. So, I'm just taking the start and end date values returned in the eventContent hook and using moment:
...
<FullCalendar
plugins={[
momentPlugin,
...
]}
eventContent={getEventDisplay}
...
/>
...
const getEventDisplay = (arg: EventContentArg) => {
const isSingleDay = isEventSingleDay(arg.event.start?.getTime() || 0, arg.event.end?.getTime() || 0);
...
}
...
const isEventSingleDay = (start: number, end: number): boolean => {
const startDate = moment(start);
const endDate = moment(end);
if (endDate.isSame(startDate, 'date')) return true;
return false;
}
Because selectOverlap function only passes through the event being overlapped, and not the selection, it is difficult to customise how to handle event creation.
In my case, we are working on a calendar/diary system, with background events showing the employee's shifts, and events showing their individual bookings.
At this point, other than the background events - absolutely no events should be able to overlap each other.
However... on top of that - we are then overlaying 'all day events' - which might be any number of things, but for examples sake, let's say they're 'staff birthdays' - therefore, you might have a couple of events today, but there will be an event in the all day section, showing someone's birthday.
I am checking for eventOverlap and doing some other checks on eventDrop and eventResize which handle different clashes, but these only work for existing events being moved or resized. I would like to do the same on event creation - which happens during the select. In order to disallow the select of spaces which already have events, I am using the example function from the selectOverlap documentation:
function(event) {
return event.rendering === 'background';
}
This works fantastically. However, if I try to create a new All Day event, it will 'overlap' any other events that exist on that day, and not pass this check.
I was hoping to be able to use the selection's object to check it for an allDay=true, but the function is only passed the existing event, and there is no way to check the selected section.
You can see a very simplified demo here:
https://codepen.io/anon/pen/NQrxOO
Try to create an allday event on the day which already has events.
Is there a better way to do this? I can completely remove the selectOverlap and do everything in the select callback instead, but I would need to essentially duplicate the overlap checks just to make this work, and I feel like that seems like overkill for something that should be relatively simple.
Is it possible to get not only the overlapped event object, but also the selection object when doing a selectOverlap function?
Current workaround is to remove the selectOverlap check, and instead do it myself within the select callback.
Below is a simplified version of a quick function I wrote to call when using select={this.handleEventCreate}:
class Diary extends React.Component {
//additional functions, state definitions, etc etc etc here.
//Define calendarRef as it will be needed in the function below
calendarRef = React.createRef();
handleEventCreate = (info) => {
// Get the Calendar API to allow unselection
let calendarApi = this.calendarRef.current.getApi();
// Get all Events
let checkEvents = calendarApi.getEvents();
// Loop through them
checkEvents.forEach(function(event){
// If it's not a background element, check whether the new element contains the existing, or vice versa.
if(event.rendering !== "inverse-background" &&
(
(event.start >= info.start && event.start <= info.end) ||
(event.end >= info.start && event.end <= info.end) ||
(info.start >= event.start && info.start <= event.end) ||
(info.end >= event.start && info.end <= event.end)
)
){
// It is an overlapping event, so we reject it.
return calendarApi.unselect();
}
});
alert('All good here to create the event.');
//extra event creation code to fire here.
}
I'm using Fullcalendar and I need to allow event overlap for one day: the last still event day can overlap on the first new event day.
For resizing and drop I resolved in this way:
eventOverlap: function(stillEvent, movingEvent) {
var a = movingEvent.start.startOf('day');
var b = stillEvent.end.startOf('day');
if(a.unix() == b.unix()){
return true;
}
return false;
}
Now I need to do the same on selecting, according to documentation, I have to use selectOverlap option by define a function, but differently of eventOverlap, this function not have an argument that include the current selection period, then I don't know how to make the check.
Somebody can say me how to do so?
UPDATE 19/05/2017:
I opened an issue on github's project repository here
I'm using FullCalendar and it is working fine.
I allow users to drag events, but sometimes I need to force the event to start on a specific date. For example, some events MUST start on a Monday, so if a user drags it to a different weekday, I'll force the event move to the previous Monday.
So, on the eventDrop callback, I have something like:
jQuery('#calendar').fullCalendar({
...
...
eventDrop: function(event, delta, revertFunc) {
if (/*must force new event start date*/) {
var duration = event.end.diff(event.start, 'd');
event.start = moment('2015-07-01');
event.end = moment('2015-07-01').add(duration, 'd');
}
}
})
Some explaining:
I must calculate the original duration, because when I change the
start date, Fullcalendar assumes the end date is the same and changes
the event duration accordingly. So it forces me to assign a new end
date (is there another way to do this?)
assigning a new date to event.start works fine
assigning a new date to event.end always returns:
TypeError: Va.time is undefined
Am I missing something, or maybe overcomplicating things?
Is the error a bug?
Thanks in advance for helping me on this!
Just modify the existing moment like this:
eventDrop: function (event) {
event.start.day(1); //Move the startdate to day 1 (Monday, 0 = Sunday)
event.end.day(1); //Also move the enddate to Monday
}
jsFiddle
I'm not sure what causes the error. It looks like it has to be something to do with setting a new momentjs object in either the event.start or event.end.
I need to send out a reminder email the DAY BEFORE a Calendar Event as well as the DAY AFTER. Unfortunately, I can't use Rules Scheduler, because the Tokens can't be manipulated with PHP. It doesn't work if I have
[node:field_event_date-datetime] -1 day
as the scheduled time.
What I've ended up doing is creating two "dummy" date fields for DAY BEFORE and DAY AFTER, and I'm trying to hook into the form, grabbing the event date, using some PHP like strtotime() to add/subtract a day, and make these the values that would go into the database.
I've tried linking to the #submit part of the form, but in phpMyAdmin, all values are NULL.
For this code i haven't even changed the date, I'm just trying to get values to appear in the database.
function mymodule_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == "event_node_form") {
$form['#submit'][] = '_mymodule_after_build';
// Makes the fields invisible
$form["field_event_day_before"]["#access"] = FALSE;
$form["field_event_day_after"]["#access"] = FALSE;
}
}
function _mymodule_after_build($form, &$form_state) {
$eventcopy = array();
// copy the value part from the Event
$eventcopy = $form['field_event_date'][0]['#value'];
// without doing any PHP yet, simply copy the values. Doesn't show up in db.
$form['field_event_day_before'][0]['#value'] = $eventcopy;
dsm($form);
return $form;
}
I've read the tutorials about using Rules Scheduler with CCK and
I'm also following Schedule email to go out based on CCK date field - not working for me
Am I using the right hooks? How do I intercept the inputted date value properly?
I don't think you are approaching your problem the correct way. If you want to try to go down the path you are proposing then you would want to look at hook_nodeapi(). You can add some code for the 'insert' and/or 'save' (or maybe even 'presave') operations so you can update your $node->field_event_day_before'][0]['#value'] and $node->field_event_day_after'][0]['#value'] fields based on the event_date value.
However, you really don't want to add extra fields for date before and date after when you can just calculate those from the event_date.
What I think the better solution is to just implement hook_cron() and have that function handle querying for all events in your database whose event day is TODAY() +1. For all those results, send out an email. Do another query that looks for any event whose event_date is TODAY() - 1 and send out an email for those results. You'll want to make sure you only run this process once in every 24 hour period.
I want to share the answer, thanks to help from the community. If you run into this same problem, try this:
function mymodule_form_event_node_form_alter(&$form, &$form_state) {
// hide these dummy fields, will fill in programatically
$form["field_event_day_before"]["#access"] = FALSE;
$form["field_event_day_after"]["#access"] = FALSE;
}
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL){
switch ($op) {
//if the node is inserted in the database
case 'insert':
if($node->type == 'event') {
// Day before (+10 hours because I'm in Hawai`i, far from GMT)
$daybefore = strtotime('-1 day +10 hours', strtotime($node->field_event_date[0]['value']));
$daybefore = date('Y-m-j\TH:i:s', $daybefore);
$node->field_event_day_before[0]['value'] = $daybefore;
// Day after (+10 hours because I'm in Hawai`i)
$dayafter = strtotime('+1 day +10 hours', strtotime($node->field_event_date[0]['value']));
$dayafter = date('Y-m-j\TH:i:s', $dayafter);
$node->field_event_day_after[0]['value'] = $dayafter;
}
}
}
The rules scheduler can then take tokens from the day_before/day_after fields, and you can use their interface for scheduling.
You can do this by using the rules module, i did this in my one project, basically you have to create two rules, one for one day before, and another for one day after. Let me know if you want any clarification.
Thanks
K