Looking to use Full Calendar and to include images as events and draggable. In short, would love to see how this example https://fullcalendar.io/js/fullcalendar-3.0.1/demos/external-dragging.html would work with small thumbnails instead of the text "My Event 1, My Event 2" etc. And have that image show up on the calendar.
Thanks in advance.
You can add any image url to your eventObject by adding the attribute "imageurl" inside of the events definition (if you just want the image, don't specify a title):
events: [
{
title : 'event',
start : '2016-10-12',
end : '2016-10-14',
imageurl:'img/edit.png', //you can pass the image url with a variable if you wish different images for each event
.
.
.
}
After that, you add the following code in the eventRender, which will add the image icon to the event (16 width and height is a good size for a thumbnail):
eventRender: function(event, eventElement) {
if (event.imageurl) {
eventElement.find("div.fc-content").prepend("<img src='" + event.imageurl +"' width='16' height='16'>");
}
},
For further details refer to this question: Add Icon(s) in first line of an event (fullCalendar)
In version Fullcalendar 5 or newer eventRender is no longer used, instead used eventContent
Full code:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
events: [
{
title: '',
start: '2020-09-02',
image_url: 'images/demo/event-calendar-1.png',
},
{
title: '',
start: '2020-09-02',
image_url: 'images/demo/event-calendar-2.png',
},
{
title: 'Event',
start: '2020-09-17',
image_url: 'images/demo/event-calendar-1.png',
},
{
title: '',
start: '2020-09-19',
image_url: 'images/demo/event-calendar-3.png',
},
{
title: 'Hello',
start: '2020-09-28'
},
],
eventContent: function(arg) {
let arrayOfDomNodes = []
// title event
let titleEvent = document.createElement('div')
if(arg.event._def.title) {
titleEvent.innerHTML = arg.event._def.title
titleEvent.classList = "fc-event-title fc-sticky"
}
// image event
let imgEventWrap = document.createElement('div')
if(arg.event.extendedProps.image_url) {
let imgEvent = '<img src="'+arg.event.extendedProps.image_url+'" >'
imgEventWrap.classList = "fc-event-img"
imgEventWrap.innerHTML = imgEvent;
}
arrayOfDomNodes = [ titleEvent,imgEventWrap ]
return { domNodes: arrayOfDomNodes }
},
});
calendar.render();
});
Related
Good morning!
I have a list view set up in full calendar and have noticed that it will not display events beyond the end of the year. With it being now mid-December, this is a bit of a problem for me. We have several event that should be displaying in this list. When I change the view to month I have to click the next month button to get next years events, but at least with that I do sucessfully see the events in question.
Is there a way for my list view calendars to roll-over and include next year entries as I approach the end of the current year?
Here is an excerpt of what I have that effects the display of my calendar:
{url:'https://calendar.mydomain.com/services/id/38djsuw3hr-au8reh39dq/organization/1/department/13/',event_properties:{color:'#6a9b49'}},
]
function data_req (url, callback) {
req = new XMLHttpRequest()
req.addEventListener('load', callback)
req.open('GET', url)
req.send()
}
function add_recur_events() {
if (sources_to_load_cnt < 1) {
$('#calendar').fullCalendar('addEventSource', expand_recur_events)
} else {
setTimeout(add_recur_events, 30)
}
}
function load_ics(ics){
data_req(ics.url, function(){
$('#calendar').fullCalendar('addEventSource', fc_events(this.response, ics.event_properties))
sources_to_load_cnt -= 1
})
}
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: '',
center: '',
right: '' //view options on top-right (supported by v2.9.1 currently)
},
viewDisplay: function(view) {
parent.setIframeHeight(iframeId) ;
},
eventClick: function(event) {
// opens events in a new window or tab
window.open(event.url,);
return false;
},
// eventDataTransform: function(rawEventData){
// return {title: rawEventData.Title
// };
// },
defaultView: $(window).width() < 765 ? 'listYear':'listYear', //carryover code from full sized calendar
nowIndicator: false, //show a marker for current time
eventLimit: 4, // allow "more" link when too many events
fixedWeekCount: false, // have blank rows on a 6 or 7 row month
listDayFormat: 'MMMM Do',
listDayAltFormat: false,
allDayDefault: false,
noEventsMessage: "No Currently Scheduled Events"
})
sources_to_load_cnt = ics_sources.length
for (ics of ics_sources) {
load_ics(ics)
}
add_recur_events()
})
All I see is my "NoEventsMessage" text when in list view. If I create a test event the occurs prior to the end of the year it shows up in list view.
Any ideas on spanning calendar end?
thanks
[Edit: I should say that the link at the top is a JSON feed, so I am not using a prefilled list of events from within my script or from within an external file]
Here is how I solved it.
I created a custom view entry for the specific default view called "list" and gave it a one year duration:
views: {
list: {
duration: { days:365 }
}
},
I reset my default view from the dynamic version I carried over from my full-sized calendar (since I am using this in a column anyway and the window width call is not needed):
From:
defaultView: $(window).width() < 765 ? 'listYear':'listYear',
To:
defaultView: 'list',
After doing those things my January entries for next year began to display in list view.
Here is what my display calls look like (If someone wants to edit this to make it look prettier and more efficient, I don't mind :).
ics_sources = [
{url:'https://calendar.mydomain.com/services/id/38djsuw3hr-au8reh39dq/organization/1/department/13/',event_properties:{color:'#6a9b49'}},
]
function data_req (url, callback) {
req = new XMLHttpRequest()
req.addEventListener('load', callback)
req.open('GET', url)
req.send()
}
function add_recur_events() {
if (sources_to_load_cnt < 1) {
$('#calendar').fullCalendar('addEventSource', expand_recur_events)
} else {
setTimeout(add_recur_events, 30)
}
}
function load_ics(ics){
data_req(ics.url, function(){
$('#calendar').fullCalendar('addEventSource', fc_events(this.response, ics.event_properties))
sources_to_load_cnt -= 1
})
}
$(document).ready(function() {
$('#calendar').fullCalendar({
header: false,
viewDisplay: function(view) {
parent.setIframeHeight(iframeId) ;
},
eventClick: function(event) {
// opens events in a new window or tab
window.open(event.url,);
return false;
},
defaultView: 'list',
nowIndicator: false, //show a marker for current time
eventLimit: 4, // allow "more" link when too many events
fixedWeekCount: false, // have blank rows on a 6 or 7 row month
listDayFormat: 'MMMM Do',
listDayAltFormat: false,
noEventsMessage: "No Currently Scheduled Events",
views: {
list: {
duration: { days: 365 },
}
}
})
sources_to_load_cnt = ics_sources.length
for (ics of ics_sources) {
load_ics(ics)
}
add_recur_events()
})
Thanks.
[edit: removed extraneous backticks from answer.]
I'm working with Fullcalendar.js and I set for each event a Simple Contextmenu that makes a specified function (change status when confirming a medical appointment). Next code sample works fine only when i have an Event in a day (eventRender):
eventRender: function(event, element) {
var originalClass = element[0].className;
element[0].className = originalClass + ' hasmenu';
$('#calendar2').contextmenu({
delegate: '.hasmenu',
menu: [{
title: 'Cambiar Estado',
cmd: 'cestado',
action: function(ui){ui.cmd = "cestado";confirmarCambioEstado(event);}
}, {
title: 'Atender Cita',
cmd: 'acita',
action: function(ui){ui.cmd = "acita";if(event.color=="#0088cc"){
actualizarEstado(3,event.id);
event.color = "yellowgreen";
calendarJ.fullCalendar('rerenderEvents');
hrefHCE.href = "HCE?idCita="+event.id;
hrefHCE.click();
}else{
advertenciaEstado();
}}
},{
title: 'Cancelar Cita',
cmd: 'ccita',
action: function(ui){ui.cmd = "ccita";event.color = "green";
confirmarCambioEstado(event);}
}, {
title: 'Eliminar Cita',
cmd: 'ecita',
action: function(ui){ui.cmd = "ecita";confirmarEliminar(event);}
}],
beforeOpen: function (event,ui) {
ui.menu.zIndex($(event.target).zIndex() + 1);
}
});
},
eventDrop: function(event, delta, revertFunc){
confirmarCambioFecha(event,revertFunc);
},
eventAfterAllRender: cambiarFuncion
});
But,only works like i want for a day. When i have two or more eventes on a same day, when in apply the functions in the contextMenu, it only makes the function with the last event of the day (if i have 3 events, the functions apply for the last event, not for the specified event i want to apply the functions)
How do i apply the same tratment for each event witouth having that issue i'm showing? i've tried to put a forEach sentence, but i don't know what i do
I tried several ways to set an icon, in the displayfield, when an item of the combo is selected with not luck, this is the fiddle for anyone to want try to help with this. very much appreciated any light.
fiddle example
The only solution is to transform the input type combo in a div with this:
fieldSubTpl: [
'<div class="{hiddenDataCls}" role="presentation"></div>',
'<div id="{id}" type="{type}" style="background-color:white; font-size:1.1em; line-height: 2.1em;" ',
'<tpl if="size">size="{size}" </tpl>',
'<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
'class="{fieldCls} {typeCls}" autocomplete="off"></div>',
'<div id="{cmpId}-triggerWrap" class="{triggerWrapCls}" role="presentation">',
'{triggerEl}',
'<div class="{clearCls}" role="presentation"></div>',
'</div>', {
compiled: true,
disableFormats: true
}
],
Override the setRawValue method of the combo like this:
setRawValue: function (value) {
var me = this;
me.rawValue = value;
// Some Field subclasses may not render an inputEl
if (me.inputEl) {
// me.inputEl.dom.value = value;
// use innerHTML
me.inputEl.dom.innerHTML = value;
}
return value;
},
and style your fake combo div like you want.
Thats because an input on HTML can't have HTML like value inside it.
Keep attenction, the get Value method will return you the HTML inside the div, and maybe you should also override it, but thats the only one method.
You will be able to get the selected value with this method:
Ext.fly(combo.getId()+'-inputEl').dom.innerHTML.replace(/<(.|\n)*?>/gm, '');
If I were you I would like to do something like this:
combo.getMyValue();
So add this property to your combo:
getMyValue:function(){
var combo=this;
if(Ext.fly(combo.id+'-inputEl'))
return Ext.fly(combo.id+'-inputEl').dom.innerHTML.replace(/<(.|\n)*?>/gm, '');
},
Here is a working fiddle
Perhaps my solution is similar to a hack, but it works in 6.7.0 and is a bit simpler.
Tested in Chrome. Theme - Material. For another theme will require minor improvements.
Sencha Fiddle live example
Ext.application({
name: 'Fiddle',
launch: function () {
var store = new Ext.data.Store({
fields: [{
name: 'class',
convert: function (value, model) {
if (value && model) {
var name = value
.replace(/(-o-)|(-o$)/g, '-outlined-')
.replace(/-/g, ' ')
.slice(3)
.trim();
model.data.name = name.charAt(0).toUpperCase() + name.slice(1);
return value;
}
}
}, {
name: 'name'
}],
data: [{
class: 'fa-address-book'
}, {
class: 'fa-address-book-o'
}, {
class: 'fa-address-card'
}]
});
var form = Ext.create('Ext.form.Panel', {
fullscreen: true,
referenceHolder: true,
items: [{
xtype: 'combobox',
id: 'iconcombo',
queryMode: 'local',
editable: false,
width: 300,
valueField: 'class',
displayField: 'name',
store: store,
itemTpl: '<div><i class="fa {class}"></i> {name}</div>',
afterRender: () => {
var component = Ext.getCmp('iconcombo');
var element = document.createElement('div');
element.className = 'x-input-el';
element.addEventListener('click', () => component.expand());
component.inputElement.parent().dom.prepend(element);
component.inputElement.hide();
component.addListener(
'change', (me, newValue, oldValue) => {
component.updateInputValue.call(me, newValue, oldValue);
},
component
);
var method = component.updateInputValue;
component.updateInputValue = (value, oldValue) => {
method.call(component, value, oldValue);
var selection = component.getSelection();
if (selection) {
element.innerHTML =
'<div><i class="fa ' + selection.get('class') + '"></i> ' + selection.get('name') + '</div>';
}
};
}
}, {
xtype: 'button',
text: 'getValue',
margin: '30 0 0 0',
handler: function (component) {
var combo = Ext.getCmp('iconcombo');
alert(combo.getValue());
}
}]
});
form.show();
}
});
Some of my Fullcalendar events have links. The links point to either public webpages, pdf documents or webpages which are restricted access.
I would like to add a class to format the links to add an icon, based on url string.
If the url contains:
"pdf" addclass "fc-pdf"
"restricted" addclass "fc-lock"
I assume it should be with and eventRender... but I'm having trouble find the right syntax. Can someone help me with this?
http://jsfiddle.net/lbriquet/oez9Ltym/
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'listDay,listWeek,month'
},
views: {
listDay: {
buttonText: 'list day'
},
listWeek: {
buttonText: 'list week'
}
},
defaultView: 'listDay',
defaultDate: '2016-09-12',
navLinks: true, // can click day/week names to navigate views
events: [{
title: 'Conference (website)',
start: '2016-09-11',
end: '2016-09-13',
url: "https://www.ted.com/talks"
}, {
title: 'Meeting (download document)',
start: '2016-09-12T10:30:00',
end: '2016-09-12T12:30:00',
url: "http://storage.ted.com/tedx/manuals/tedx_speaker_guide.pdf"
}, {
title: 'Lunch',
start: '2016-09-12T12:00:00'
}, {
title: 'Meeting (members only)',
start: '2016-09-12T14:30:00',
url: "http://www.dictionary.com/browse/restricted"
}, {
title: 'Happy Hour',
start: '2016-09-12T17:30:00'
}, {
title: 'Dinner',
start: '2016-09-12T20:00:00'
}],
eventRender: function eventRender(event, element, view) {
}
});
The way I got this to work was by adding a type to the events simply because I think it would be easier than dealing with regex that might not always work. So events don't need a type but they can have a type pdf, restricted or whatever else you need. In eventRender I added the following:
eventRender: function eventRender(event, element, view) {
if(typeof event.type !== 'undefined') {
if(event.type === 'pdf') {
element.addClass('fc-pdf');
} else if(event.type === 'restricted') {
element.addClass('fc-lock');
}
}
}
A check to see if the type is provided or not and then if statements for adding the class based on the type. I also had to make a small change to the css selector, changing a.fc-lock to .fc-lock a to allow it to display properly. Here is the JS Fiddle showing this.
My question is pretty straightforward: I want to load a details page from the database on eventClick. So I just need to know how to access the event attributes on the click.
If my question is in any way ambiguous, please let me know and I'll clarify.
Thank you!
The eventClick function returns the original event and it will preserve the attributes you've set (unless they have the same key as something used internally).
$('#calendar').fullCalendar({
events: [
{
title: 'My Event',
start: '2010-01-01',
myId: 123
}
// other events here
],
eventClick: function(event) {
if (event.myId) {
alert(myId);
}
}
});
For version 5
Source : https://fullcalendar.io/docs/eventClick
eventClick: function(info) {
alert('Event: ' + info.event.title);
alert('Coordinates: ' + info.jsEvent.pageX + ',' + info.jsEvent.pageY);
alert('View: ' + info.view.type);
// change the border color just for fun
info.el.style.borderColor = 'red';
}
In version 5.11.3, You can do it like this.
First, you have to set id to an event
events: [
{
id: 1,
title: "All Day Event",
start: "2020-09-01",
color: '#FF0000',
},
],
Then you can access it by with event object.event.id
eventClick: function (info) {
alert('Event: ' + info.event.id);
}
You can also pass in info as a parameter to get other values from calendar
eventClick: (info)=> {
alert(info.id); //ID
var eventTitle = info.title; //TITLE
var eventVenue = info.venue; //VENUE
var eventDescription = info.description; //DESCRIPTION
}