Add event into the event calendar - javascript

How do I add an event into another event?
example
$('#calendar').fullCalendar({
events: [
{
start: new Date(),
end: new Date(),
events: [ {}, {} ] // ???
}
]
});
see screenshot

This is not possible without heavy custom modifications. Very much beyond the scope of an SO question.
The closest you can get easily is to use background events as "parent" events and regular events as child events. Something like the following:
var sourceEvents = [
{
id: 1,
start: moment(),
end: moment().add(6,'h'),
childEvents: [{
start: moment().add(1,'h'),
end: moment().add(2,'h'),
}, {
start: moment().add(3,'h'),
end: moment().add(5,'h'),
}],
}
];
$("#calendar").fullCalendar({
defaultView: "agendaWeek",
events: function( start, end, timezone, callback ) {
var events = [];
sourceEvents.forEach(function(event){
event.rendering = "background";
events.push(event);
event.childEvents.forEach(function(childEvent){
// you could do some checks to make sure they are in bounds
// you could also do some color coding here
childEvent.parentId = event.id;
events.push(childEvent);
});
});
callback(events);
},
});
JSFiddle

Related

Not able to drop external elements on calendar

when I drag an external element on the calendar, I am not able to create an event on the calendar through it. eventReceive() callback is also not getting fired.
I have set the droppable option to true as well. Can someone please help? Have a look at the code:
HTML:
<div class="fc-event">Drag me !!</div>
JS:
$('.fc-event').each(() => {
// store data so the calendar knows to render an event upon drop
$(this).data('event', {
title: $.trim($(this).text()), // use the element's text as the event title
stick: true, // maintain when user navigates (see docs on the renderEvent method)
duration: '02:00',
create: true,
});
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0, // original position after the drag
});
});
const calendarEl = document.getElementById('calendar');
calendar = new Calendar(calendarEl, {
themeSystem: 'standard',
selectable: true,
droppable: true,
columnHeader: true,
selectMirror: true,
editable: true,
plugins: [interactionPlugin, dayGridPlugin, timeGridPlugin],
eventResourceEditable: true,
select(selectionInfo) {
showTaskCreationPopup(selectionInfo.start, selectionInfo.end);
},
eventReceive(element) {
console.log('event received');
createTask(element.event);
},
drop(info) {
console.log('dropped');
createTask(info.jsEvent);
},
eventDrop(info) {
console.log('event dropped');
},
header: {
left: 'prevYear prev today next nextYear',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay',
},
buttonText: {
// eslint-disable-next-line new-cap
prevYear: new moment().year() - 1,
// eslint-disable-next-line new-cap
nextYear: new moment().year() + 1,
},
});
calendar.render();
The way that I was able to achieve this was not through the eventReceive -neither eventDrop- event but using the 'drop' event. The signature is something like:
customDrop = ({ resource, date, draggedEl: { id } }) => {})
var containerEl = document.getElementById('external-events-list');
var eventEls = Array.prototype.slice.call(
containerEl.querySelectorAll('.fc-event')
);
eventEls.forEach(function(eventEl) {
if (eventEl.textContent == "Event1") {
new Draggable(eventEl, {
eventData: {
id: 1,
title: eventEl.innerText.trim(),
color: 'Orange',
textColor:'black'
}
});
} else if (eventEl.textContent == "Event2") {
new Draggable(eventEl, {
eventData: {
id: 2,
title: eventEl.innerText.trim(),
color: '#ccccff',
textColor:'black'
}
});
}}); // end eventEls.forEach

Allow events to be dragged only onto background events

I am managing appointments on fullcalendar. I have available slots of time where I can create new appointments. Also I can drag appointments onto available time slots which are shown as background events.
I only want the drop functionality on background event slots.
I have tried the eventOverlap method but it only works when the event is dropped on a background event. If the event is dropped elsewhere then I am unable to detect whether I am dropping the event on background event or on empty slot.
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
defaultView: 'timeGridWeek',
// height: 1080,
plugins: ['dayGrid', 'timeGrid', 'interaction'],
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
events: {
url: getUrl(),
failure: function() {
toastr.error('Unable to load calendar data, Please try later');
},
success: function() {
}
},
loading: function(bool) {
},
defaultDate: Date.now(),
editable: true,
eventLimit: true,
eventClick: function(info) {
if (info.event.extendedProps.type == 'Calendar') {
showCreateModal(info.event);
}
if (info.event.extendedProps.type == "Appointment") {
showUpdateModal(info.event);
}
},
eventOverlap: function(stillEvent, movingEvent) {
return stillEvent.extendedProps != '' && stillEvent.extendedProps.type === 'Calendar' ? true : false;
},
eventDrop: function(info) {
// check if event is being dropped on past date / slot
if (moment(info.event.start) < moment()) {
info.revert();
return;
}
// check if event is being dropped on future slot
if (moment(info.event.start) > moment()) {
swal({
title: "Are you sure?",
text: "You are about to re-schedule this appointment!",
icon: "warning",
// buttons: true,
buttons: ["No", "Yes !"],
dangerMode: true,
})
.then((response) => {
if (response) {
submitForm(false, true, info.event);
} else {
info.revert();
}
});
}
}
});
calendar.render();
This is what I want:
You're correct that eventOverlap doesn't help you here, because it's only triggered when the event is dropped onto a background event. It doesn't help you when the event is dropped somewhere else.
In fullCalendar 4 you can achieve what you need via the eventConstraint setting. This allows you to limit event dragging to specific windows of time. As the documentation says, you can provide a groupId value to this setting, and then
...events that are being dragged or resized must be fully contained by at least one of the events linked to by the given groupId.
All you need to do as well as that is give all your background events the same groupId.
For example, if you set:
eventConstraint: 1
and then have entries such as these within your event data:
{
start: "2019-07-10 09:00",
end: "2019-07-10 12:00",
rendering: "background",
groupId: 1
},
{
start: "2019-07-11 09:00",
end: "2019-07-11 12:00",
rendering: "background",
groupId: 1
},
This would mean that you would only be allowed to drag or resize an existing calendar event if you drag/resize it so that it falls entirely within the time periods covered by those background events which have a groupId of 1.
Here's a working demonstration: https://codepen.io/ADyson82/pen/jjdEjB

FullCalendar v3 - Change Event Source on View Change

I'm using FullCalendar v3 (latest) with a PHP backend.
I'm returning a JSON array from the backend broken up into 2 arrays. The first contains event details (a list of orders for the day, with the order# as the title), and the second contains a daily summary (with a sum of orders and work hours as the title). The array looks like this:
{"events":[{"id":709989,"item_no":"ABC123","title":709989,"color":"red","start":"2019-05-14","end":"2019-05-14","allDay":true,"total_hours":3,"remaining_hours":1.5},{"id":709990,"title":709990,"item_no":"ABC345","color":"red","start":"2019-05-15","end":"2019-05-15","allDay":true,"total_hours":5.7,"remaining_hours":3.2}],"summary":[{"id":338823,"title":"Orders: 14\rHours:28.33\rRemaining Hours:13.33","start":"2019-05-14","end":"2019-05-14","allDay":true},{"id":338824,"title":"Orders: 3\rHours:14.2\rRemaining Hours: 12.2","start":"2019-05-15","end":"2019-05-15","allDay":true}]}
There are other properties but these are the basics.
What I'm trying to do is change the array that's used as the event source depending upon which view is selected. I've tried custom event rendering, custom view rendering, multiple event sources (even though it's expensive from a data point-of-view, the # of records aren't so numerous that it greatly effects performance).
The custom view name is customMonth. When this view is selected, I just want to render the summary data (from the summary array). If any of the other views are selected (I'm using basicWeek, month and listWeek), render the events array.
let vname;
$("#calendar").fullCalendar({
defaultDate: new Date(),
defaultView: 'month',
eventRender: function(eventObj, $el, view) {
let n = view.name;
if(n=='customMonth')
{
vname = 'customMonth';
$el.popover({
title: eventObj.title,
content: eventObj.total_hours,
html: true,
trigger: 'hover',
placement: 'auto',
container: 'body'
});
} else {
vname = n;
$el.popover({
title: "Work Order " + eventObj.title,
content: '<strong>Item#</strong>: ' + eventObj.item_no + '<br />' + '<strong>Total Hours</strong>: ' + eventObj.total_hours + '<br />' + '<strong>Remaining Hours</strong>: ' + eventObj.remaining_hours,
html: true,
trigger: 'hover',
placement: 'auto',
container: 'body'
});
}
},
events: function(start, end, timezone, callback){
$.ajax({
url: '/myendpoint',
type: 'POST',
dataType: 'json',
data: {
action: 'get-calendar-summary',
cell: selected_cell
},
success: function(data) {
let events = [];
if(vname=='customMonth') {
obj = data.summary;
$(obj).each(function() {
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('dept_due_dt'),
end: $(this).attr('dept_due_dt'),
total_hours: $(this).attr('total_hours'),
remaining_hours: $(this).attr('remaining_hours'),
order_count: $(this).attr('day_order_count'),
has_late_order: $(this).attr('has_late_order'),
allDay: true,
earliest_date: $(this).attr('earliest_date')
});
});
} else {
obj = data.event_results;
$(obj).each(function() {
events.push({
id: $(this).attr('id'),
color: $(this).attr('color'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
earliest_date: $(this).attr('earliest_date'),
item_no: $(this).attr('item_no'),
total_hours: $(this).attr('total_hours'),
remaining_hours: $(this).attr('remaining_hours')
});
});
}
callback(events);
},
error: function(err) {
console.log(err);
}
});
},
views: {
customMonth: {
type: 'month',
buttonText: 'overview'
}
},
viewRender: function(view, el) {
let lastview;
if(view.name=='customMonth') {
if(lastview == 'customMonth') {
return false;
} else {
view.unrenderDates();
view.renderDates();
$("#calendar").fullCalendar('rerenderEvents');
}
lastview = 'customMonth';
} else {
if(lastview=='customMonth') {
view.unrenderDates();
view.renderDates();
$("#calendar").fullCalendar('rerenderEvents');
}
lastview = view.name;
}
},
header: {
left: 'prev,next',
center: 'title',
right: 'basicWeek,month,listWeek,customMonth'
},
themeSystem: 'bootstrap3',
timeZone: false,
weekends: false,
//tried with and without lazyFetching
lazyFetching: true
});
I'd appreciate any guidance. I've searched StackOverflow (this seems like the closest, but I followed exactly and it didn't work (switching out viewDisplay for viewRender)), Github, and all other sources I can think of.
Here a simplified example of what you are trying to achieve (I hope I well understand your problem) :
HTML :
<div id='calendar'></div>
Javascript :
$(document).ready(function() {
var ev1 = {"events":[{"id":709989,"item_no":"ABC123","title":'Event from source 1',"color":"red","start":"2019-05-14","end":"2019-05-14","allDay":true,"total_hours":3,"remaining_hours":1.5}]};
var ev2 = {"events":[{"id":709989,"item_no":"ABC123","title":'Event from source 2',"color":"blue","start":"2019-05-14","end":"2019-05-14","allDay":true,"total_hours":3,"remaining_hours":1.5}]};
$('#calendar').fullCalendar({
defaultDate: new Date(),
defaultView: 'month',
viewRender: function(view) {
if(view.type === 'basicWeek') {
$('#calendar').fullCalendar( 'removeEventSource', ev1 );
$('#calendar').fullCalendar( 'addEventSource', ev2 );
return;
}
},
header: {
left: 'prev,next',
center: 'title',
right: 'basicWeek,month,listWeek,customMonth'
},
});
$('#calendar').fullCalendar( 'addEventSource', ev1 );
});
And the codepen to try it.
It uses the callback function viewRender() to detect when a view change and addEventSource()/removeEventSource() to change the data. So when you change the view from month to week it will change the source events.

How to create array from Model?

Im new to javascript and I have this code where I should pass or convert to jQuery. I have tried some code but it doesn't work. How can I do it properly?
Here is what it should look like:
<script>
$('#calendar').fullCalendar({
defaultDate: '2017-10-12',
editable: true,
eventLimit: true, // allow "more" link when too many events
events: [
{
title: 'Juan Dela Cruz',
start: '2017-10-01T10:30:00',
},
{
title: 'Juan Dela Cruz',
start: '2017-10-12T10:30:00',
},
{
title: 'Juan Dela Cruz',
start: '2017-10-27T12:00:00'
}
]
});
and here is what I have tried:
<script>
var x = [];
#foreach(var item in Model)
{
#:x.push(title='#Html.DisplayFor(x=>item.Patient.LastName)', start='#Html.DisplayFor(x=>item.ScheduleDate)')
}
$('#calendar').fullCalendar({
defaultDate: '2017-10-12',
editable: true,
eventLimit: true, // allow "more" link when too many events
events: x
});
You're iterating correct the Model using #foreach statement.
The problem is at this line:
#:x.push(title='#Html.DisplayFor(x=>item.Patient.LastName)', start='#Html.DisplayFor(x=>item.ScheduleDate)')
You have to push an object in following way:
#:x.push({title:'#item.Patient.LastName', start:'#item.ScheduleDate'});
The statement foreach in jQuery is $.each and this a simple sample to do that :
$.each( obj, function( key, value ) {
alert( key + ": " + value );
});

Adding options with an Array

I'm using the fullCalendar jQuery plugin and it has options for adding events to the calendar as such:
$('#calendar').fullCalendar({
editable: false,
events: [
{
title: 'Just some random event',
start: '2011-04-30'
},
{
title: 'Long Event',
start: '2011-05-01'
}
]
});
I'm trying to implement this into a Drupal 7 view. I will have loop through a list of elements and grab the hidden timestamp to populate the calendar. I know how to loop through the elements and grab the values, but I'm not sure how to add the values to an array I could use to populate the events option.
Create an empty array:
var events = [];
Then you can add objects to it in your loop:
var title = "Just some random event";
var start = "2011-04-30";
events.push({ title: title, start: start });
Now you can use the array in the calendar:
$('#calendar').fullCalendar({
editable: false,
events: events
});
Have you tried something like that?
var yourEventsArray = [];
$.each(data, function(index, value) {
yourEventsArray.push({
title: value.title,
start: value.timeStamp
});
});

Categories

Resources