I'm trying to get the fullCalendar JS application to display events only when on the agendaView view, not on the month view.
This is my current code. The problem is the events function is only called once, on the initial page load. According to documentation (and another site I have with fullCalendar) this function should call every time I change view, or date range. It does not.
$('#calendar').fullCalendar({
events: function ( start, end, timezone, callback ) {
var view = $('#calendar').fullCalendar('getView');
console.log(view.name);
if(view.name == 'agendaDay') {
$.ajax({
type: 'POST',
url: 'index.php?events=true',
data: {
start: start,
end: end
},
async: true,
success: function ( data ) {
callback(data);
}
});
}
},
dayClick: function ( date, jsEvent, view ) {
if(view.name == 'month' && jsEvent.currentTarget.className.indexOf('date-disabled') <= -1) {
$('#calendar').fullCalendar('changeView', 'agendaDay');
$('#calendar').fullCalendar('gotoDate', date);
} else if(view.name == 'agendaDay') {
var check = moment(date).format('YYYY-MM-DD');
var today = moment(new Date()).format('YYYY-MM-DD');
if(check > today) {
alert(date);
}
}
},
header: {
left: 'title',
center: '',
right: 'today month,agendaDay prev,next'
},
dayRender: function ( date, cell ) {
var check = moment(date).format('YYYY-MM-DD');
var today = moment(new Date()).format('YYYY-MM-DD');
if(check <= today) cell[0].className += ' date-disabled';
}
});
I know this for fact as the console.log only logs once, the word month. So it's only called when I refresh the page, first load it. Not when changing views which it should.
I was missing the lazyFetching option. This must be a new option in v2 as I was not expecting it.
http://arshaw.com/fullcalendar/docs/event_data/lazyFetching/
My code was correct. I simply needed to tell fullCalendar to get the events at EVERY change of the view and anything else that happened event wise.
lazyFetching: false,
This now works with my code.
Related
Hello, everybody. I am using fullcalendar in my symfony project(Symfony + RiotJS). I want to load the events dynamically when I press 'prev' or 'next' button. So I make a new calendar when the page is mounted and set the calendar events as 'null'. As you can see on the code, I called the loadItems() function to load the events again when I press 'prev' or 'next' button. But I can't sure how to update the events of calendar in the loadItems() function. I'd really appreciate if someone knows how to fix it. I will wait for reply.Thanks.
onMounted() {
self = this;
let calendarEl = this.$('#calendar');
this.state.calendar = new Calendar(calendarEl, {
plugins: [ dayGridPlugin, timeGridPlugin, listPlugin ],
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek'
},
buttonText: {
today: 'Heute',
month: 'Monat',
week: 'Woche',
day: 'Tag',
},
datesSet: function() {
let view = this.currentData.dateProfile.renderRange;
let start = view.start.toISOString().substring(0, 10);
let end = view.end.toISOString().substring(0, 10);
if (start != getSearchParam('begin')) {
updateSearchParam('begin', start);
updateSearchParam('end', end);
self.loadItems();
}
},
events: this.state.events,
initialDate: getSearchParam('date', '') ? getSearchParam('date', '') : this.moment().format('Y-MM-DD'),
});
this.state.calendar.setOption('locale', 'de');
this.state.calendar.render();
updateSearchParam('date', '');
this.update();
this.loadItems();
},
And this is the loadItems() function.
loadItems() {
this.state.loading = true;
this.update();
if (this.state.request) {
this.state.request.abort();
}
this.state.request = this.API.get('/events', this.getParams());
this.state.request.then(response => {
this.state.items = response.data.items;
this.state.filteredItems = null;
this.state.total = response.data.total;
this.state.events = [];
response.data.items.forEach( item => {
let event = {
id: item.id,
title: item.event.name,
start: this.moment(item.begin).format('Y-MM-DD'),
end: this.moment(item.end).format('Y-MM-DD'),
backgroundColor: item.event.type.bgColor,
borderColor: '#ffffff',
textColor: this.getTextColor(item.event.type.bgColor),
};
this.state.events.push(event);
});
this.state.loading = false;
this.update();
//after I gets the events I want to update the events of calendar here
//this.state.calendar.refetchEvents();
this.update();
this.state.request = null;
});
return this.state.request;
},
I just focused how to update events when I press the 'prev' and 'next' button.
I searched a lot about the method and there were many solutions.
For example:
$('#calendar').fullCalendar('updateEvents', events)
$('#calendar').fetchEvents()
But these methods are not working on my problem.
Finally, I found a simple method.
It is a setOption() method.
As you can see on my above code, there are options like 'datesSet' and 'events'.
The 'datesSet' option is called everytime when I press the buttons (prev, next, today, month, week and etc).
And the 'events' option is for events to show on the current calendar view.
I used setOption() method like this.
this.state.calendar.setOption('events', this.state.events);
It worked well for me.
I suggest the people who read my question and answer, to read the tutorials and documentations carefully.
Fullcalendar is really well-built javascript package and we can use it very simply.
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 currently trying to get an event (type of background) when the DayClick is trigger.
I can't use the EventClick trigger because of the background type (I don't know why but nothing happen in my case, something wrong from FullCalendar ?).
This is my code for the init :
$('#calendarRoomUnavailable').fullCalendar({
height: 'auto',
header: {
left : '',
center: 'title',
right: ''
},
defaultView: 'year',
defaultDate: getDateFilterRoomAvailable(),
lang: 'fr',
firstDay: 1,
columnFormat: 'ddd D/M',
selectable : false,
weekends: false,
navLinks : false,
events: basePath + '/agenda/datalist/room_available',
viewRender: function (view, element) {
},
eventRender: function(event,element){
if(event.rendering === "background"){
element.data(event); //store the event data inside the element
}
},
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
},
editable:false,
});
Quick look
What I want:
When I click on a day, I want the get the event(background) related to the day (I've got only one event per day in my calendar).
Currently I'm working with the eventRender + dayClick :
eventRender: function(event,element){
if(event.rendering === "background"){
element.data(event); //store the event data inside the element
}
},
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
[...]
}
With the console.log JSEvent on the DayClick, I know it get me the wrong <td> :
Img
Because, when I try to get the target <td> with the class fc-bgevent, nothing happens :
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
if (jsEvent.target.classList.contains('fc-bgevent')) {
console.log($(jsEvent.target).data());
}
If I try to go to the HTML element target getted by the jsEvent, it shows me the wrong <td> and I can't do anything with that ...
HTML Debug
Does someone know how to bypass that ?
Thanks !
Code to get one event from a date :
function getEventFromDate(date) {
var allEvents = [];
allEvents = $('#calendarRoomUnavailable').fullCalendar('clientEvents');
var event = $.grep(allEvents, function (v) {
return +v.start === +date;
});
if (event.length > 0) {
return event[0];
} else {
return null;
}
}
After the #ADyson comments, my final function look like this :
function getEventFromDate(date) {
var eventToReturn = null;
$('#calendarRoomUnavailable').fullCalendar('clientEvents', function(event) {
var event_start = formatDateYmd(new Date(date),'-');
var date_formated = formatDateYmd(new Date(event.start),'-');
if(event_start === date_formated) {
eventToReturn = event;
}
});
return eventToReturn;
}
with a small function to get a formated date without library like Moment.js or Date.js:
function formatDateYmd(value,$delimiter)
{
var year = value.getFullYear();
var month = (value.getMonth()+1) < 10 ? '0'+(value.getMonth()+1) : (value.getMonth()+1);
var day = value.getDate() < 10 ? '0'+value.getDate() : value.getDate();
return year + $delimiter +
month + $delimiter +
day;
}
I hope to find something more performant, but this one divide the execution time by two.
Keep an eye on it
Thanks again.
How can I order events in fullCalendar first by start date?
Example:
An event which starts first will show on top and then one which starts later will be later
If two events have same the start date then, order them by end date
i.e
an event which ends earlier will be shown first, followed by an event which ends later.
Calendar Display
Events Order
var args = jQuery.parseJSON(emCalendarArgs);
var Jobj = args.events;
// Setup FullCalendar
(function() {
//var language = jQuery('#pg_lang').val();
//alert(language+ 'dsfsd');
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
var language = langg;
var mn_text, week_text, day_text, list_text;
//alert(mn_text);
var args = jQuery.parseJSON(emCalendarArgs);
var Jobj = args.events;
console.log(Jobj);
jQuery('#events-full-calendar').fullCalendar({
allDaySlot: false,
editable: true,
lang: 'he',
handleWindowResize: true,
eventOrder: 'start,end',
header: {
left: 'today prev,next',
center: 'title',
right: 'month,basicWeek,basicDay'
},
buttonText: {
month: mn_text,
week: week_text,
day: day_text
},
eventLimit: {
'month': 3, // adjust to 4 only for months
'default': false // display all events for other views
},
axisFormat: 'HH:mm',
timeFormat: {
agenda: 'H:mm{ - h:mm}'
},
slotEventOverlap: false,
events: Jobj,
timeFormat: 'H:mm',
});
}());
I found a Solution to it. For any one else looking for the solution to this, I changed a function in fullcalendar.js:
compareSegs: function(seg1, seg2) { return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1) compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs); }
to :
compareSegs: function(seg1, seg2) {
if(this.view.name=="basicWeek" || this.view.name=="month" || this.view.name=="basicDay"){ // ordering events by color in ListView
return seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs);
}
else{
return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first
seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first
seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs);
}
}
and used below code in fullcalendar function
eventOrder: 'start, end'
in my fullcalendar call
I'm working on a website, asp.net MVC kind of thing. On the home page, I have two alternate views. One is a jquery FullCalendar, and one is an index view, both displaying events from a database.
I can currently change the month being viewed in either, but I want to be able to link them up, so that for example changing to view april 2013 in the calendar and then clicking "index view" will take me to april 2013 in the index view, rather than the default.
My "GetEventsForCalendar" method is as follows:
[HttpPost]
public virtual ActionResult GetEventsForCalendar(long start, long end)
{
var startDateTime = start.ToDateTime();
var endDateTime = end.ToDateTime();
var listOfEvents = eventRepository.List.Where(e => e.ToDate >= startDateTime
&& e.FromDate <= endDateTime).ToList() .Select(eventSerialiser.SerialiseForFullCalendarJS);
return Json(listOfEvents);
}
But I can't find anywhere in the codebase where it is given these parameters. The only place the function is specified is in the calendar partial view scrips section:
#section scripts {
#Scripts.Render(Links.Bundles.Scripts.calendar)
#Scripts.Render(Links.Bundles.Scripts.events_calendar)
<script type="text/javascript">
$(document).ready(function() {
SohoHouse.EventsCalendar.setup("#Url.Action(MVC.Events.GetEventsForCalendar())");
})
</script>
}
I think the details of the month being viewed are persisted in a cookie, but I'm not sure how to access this from my index view.
If you need any other code then please ask, I'm very new to programming and stack overflow so I'm still not sure how to ask questions well :)
Managed to get this working in the end: abandoned the idea of a seperate view for the index, and instead used the jquery to create a table with a list view of the events. Then used a button to toggle between the two. For reference, the calander.js looked something like this:
var report = $("#report");
var calendar = $("#calendar .fc-content");
report.hide();
$("#toggle-view").click(function() {
calendar.toggle();
report.toggle();
$("#calendar").fullCalendar("refetchEvents");
$("#calendar").fullCalendar("render");
updateToggleButtonText();
});
function updateToggleButtonText() {
$("#toggle-view").text(report.is(":visible") ? "View Calendar" : "View List");
}
function setUpCalendar() {
$("#calendar").fullCalendar({
events: {
url: getEventsUrl,
type: "POST",
eventDataTransform: addReportRow
},
timeFormat: "H:mm{ - H:mm}",
allDayDefault: false,
eventBorderColor: "gray",
header: {
left: "prev,next",
center: "title",
right: null
},
weekMode: "variable",
loading: function(isLoading) {
if (isLoading) {
$("table#report > tbody:last").empty();
}
},
allDaySlot: false
});
}
function addReportRow(data) {
var calendarMonth = $("#calendar").fullCalendar("getDate").getMonth();
var startDate = new Date(data.start);
var endDate = new Date(data.end);
if (startDate.getMonth() > calendarMonth || endDate.getMonth() < calendarMonth) {
return null;
}
var tableDetails = [
data.title,
$.fullCalendar.formatDate(startDate, "dd MMMM yyyy"),
$.fullCalendar.formatDate(endDate, "dd MMMM yyyy"),
data.published ? "Published" : "Not Published"
];
var row = $("<tr></tr>");
for (var i = 0; i < tableDetails.length; i++) {
row.append($("<td></td>").text(tableDetails[i]));
}
$("table#report > tbody:last").append(row);
return data;
}
function gotoDateFromCookie() {
var calendarDate = $.cookie("calendarDate");
if (calendarDate !== null && calendarDate !== "Invalid Date") {
$("#calendar").fullCalendar("gotoDate", new Date(calendarDate));
$.cookie("calendarDate", null);
}
}
function storeDateAsCookie() {
var calendarDate = $("#calendar").fullCalendar("getDate");
$.cookie("calendarDate", calendarDate);
}
window.eventDropdownChanged = function() {
location.reload();
};
};