agendaWeek: events not shown - fullcalendar

what I'm possibly doing wrong!?
I do NOT see my events when 'defaultView: agendaWeek' (or agendaDay).
PS: basicWeek (or basicDay) works just fine.
BUT: when clicking the 'month' view: ALL events are showing correctly in 'month' view! Then, when again clicking 'week' (or Day) I see them ALL correctly as agendaWeek (or agendaDay) view!
I'm running fullcalendar: 3.6.2
PS: sorry, posted same issue in non-related forum
must miss a stupid thing - thanks for your time and hints, ed
<script type="text/javascript">
(function ($) {
#if (Model.tagColorsEnabled && Model.tagColors != null) {
<text>
var tagSet = [
#foreach (var tc in Model.tagColors)
{
#Display(tc)
}
];
var tagIndex = [];
for (var tag in tagSet) {
tagIndex[tagSet[tag].slug] = tag;
}
</text>
}
$('#calendar').fullCalendar({
locale: '#culture',
timeFormat: 'HH:mm', //eddie timeFormat: 'HH:mm{-HH:mm}',
slotLabelFormat: 'HH:mm', //eddie timeFormat: 'HH:mm{-HH:mm}',
// height: 500, //added by eddie
// allDay: false, // eddie
header: {
left: 'prev,next today',
center: 'title',
right: 'month, agendaWeek, agendaDay',
// right: 'month, agendaWeek, agendaDay' // eddie
},
eventRender: function (event, element) {
var colors = { bg : event.defaultBackgroundColor, br: event.defaultBorderColor, fg: event.defaultTextColor };
#if (Model.tagColorsEnabled)
{
<text>
var min = 100;
for (var klassNdx in event.className) {
var klass = event.className[klassNdx];
if (klass.substring(0, 4) === "tag-") {
var entry = tagIndex[klass.substring(4)];
if (entry !== undefined) {
if (entry < min) {
colors = tagSet[entry];
min = entry;
}
}
}
}
</text>
}
$(element)
.css("background-color", colors.bg)
.css("color", colors.fg)
.css("border-color", colors.br);
},
editable: false,
events: {
url: '#Url.Content("~/_Calendar/" + Model.queryId)',
},
// defaultView: '#Model.defaultView',
// defaultView: 'basicWeek',
defaultView: 'agendaWeek',
weekends: #Model.showWeekends
//viewRender: function (v, e) { alert("Rendering view"); }
});
})(jQuery);
</script>

solved - sort of!
When using 'defaultView: basicWeek / agendaWeek'; fact is that I get different DateTime info like:
basicWeek: '2017-1-06' --> which in turn works correctly!
agendaWeek: '2017-1-06T00:00:00' --> which results in an error!
When stripping off 'T00:.....' --> problem solved
I know that this is probably not the 'clean' solution BUT for the time being ..... will further check if time is available!
For now I like to thank ADyson for his advise and time spent.

Related

onDragStop tells me jsEvent is undefined

I'm trying to make it possible to drag events to an external div and back into the calendar again. However, whenever I drop an event I get TypeError: jsEvent is undefined.
I'm not entirely sure why it is doing this, this should be a valid parameter that is passed to the function of eventDragStop.
I'm using the latest FullCalendar 4.
Here is my code
// Load the CSS stuff
import {Tooltip} from "bootstrap";
require('#fortawesome/fontawesome-free/css/fontawesome.min.css');
require('#fortawesome/fontawesome-free/css/brands.min.css');
require('#fortawesome/fontawesome-free/css/solid.min.css');
require('../css/app.scss');
// Load the JS stuff
let $ = require('jquery');
require('bootstrap');
require('./libs/navbar.js');
require('jquery-ui/ui/widgets/draggable');
import apiclient from "./libs/apiclient";
import { Calendar } from '#fullcalendar/core';
import dayGridPlugin from '#fullcalendar/daygrid';
import timeGridPlugin from '#fullcalendar/timegrid';
import interactionPlugin from '#fullcalendar/interaction';
import bootstrapPlugin from '#fullcalendar/bootstrap';
// $(document).ready(function () {
//
// });
document.addEventListener('DOMContentLoaded', () => {
/* initialize the external events
-----------------------------------------------------------------*/
$('#external-events .fc-event').each(function() {
// 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)
});
// 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
});
});
let calendarEl = document.getElementById('calendar-holder');
let calendar = new Calendar(calendarEl, {
views: {
jira: {
type: 'dayGridWeek',
duration: {months: 3},
buttonText: 'Jira'
}
},
defaultView: 'jira',
themeSystem: 'bootstrap',
editable: true,
droppable: true,
firstDay: 1,
contentHeight: 'auto',
weekNumbersWithinDays: true,
weekNumbers: true,
eventSources: [
{
url: "/fc-load-events",
method: "POST",
extraParams: {
filters: JSON.stringify({})
},
failure: () => {
// alert("There was an error while fetching FullCalendar!");
},
},
],
header: {
left: 'prev,next today',
center: 'title',
right: 'jira,dayGridMonth,timeGridWeek',
},
plugins: [ bootstrapPlugin, interactionPlugin, dayGridPlugin, timeGridPlugin ], // https://fullcalendar.io/docs/plugin-index
timeZone: 'UTC',
eventRender: function(info) {
var tooltip = new Tooltip(info.el, {
title: info.event.title+'<br>'+info.event.extendedProps.assignee,
placement: 'top',
trigger: 'hover',
container: 'body',
html: true
});
},
dragRevertDuration: 0,
drop: function() {
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
$(this).remove();
}
},
eventDragStop: function( event, jsEvent, view ) {
if(isEventOverDiv(jsEvent.clientX, jsEvent.clientY)) {
$('#calendar-holder').calendar('removeEvents', event._id);
var el = $( "<div class='fc-event'>" ).appendTo( '#external-events-listing' ).text( event.title );
el.draggable({
zIndex: 999,
revert: true,
revertDuration: 0
});
el.data('event', { title: event.title, id :event.id, stick: true });
}
}
});
calendar.render();
let isEventOverDiv = function(x, y) {
var external_events = $( '#external-events' );
var offset = external_events.offset();
offset.right = external_events.width() + offset.left;
offset.bottom = external_events.height() + offset.top;
// Compare
if (x >= offset.left
&& y >= offset.top
&& x <= offset.right
&& y <= offset .bottom) { return true; }
return false;
}
});
I figured out that the jsEvent is now located in event.jsEvent. This is where I can get the position from now.

fullcalendar - multiple sources to turn off and on

I've a calendar that I want to list various types of event on and enable a checkbox filter to show/hide those kind of events.
Is there a way to say on this action, ONLY load from 1 data-source AND remember that URL on month next/prev links?
I've started using eventSources, but it loads them all, rather than the one(s) I want.. Here's what I have.
var fcSources = {
all: {
url: tournament_url + '/getCalendar/?typefilter=[1,2]'
},
type1: {
url: tournament_url + '/getCalendar/?typefilter=[1]'
},
type2: {
url: tournament_url + '/getCalendar/?typefilter=[2]'
}
};
These URLS all provide a json string of events, based on the types prrovided.
Here's my calendar:
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek'
},
firstDay: 1, // Monday = 1
defaultDate: new Date(), // Now
editable: true,
eventSources: [ fcSources.all ],
events: fcSources.all,
nextDayThreshold: '00:00:00',
... etc etc
Above my calendar I have this:
input type="checkbox" name="event_filter[]" value="type1" /> Type 1
input type="checkbox" name="event_filter[]" value="type2" /> Type 2
And finally , two Jquery fucntions.. one to get all the filters:
function getFilters(getName) {
var filters = [];
var checked = [];
$("input[name='"+getName+"[]']").each(function () {
filters.push( $(this).val() );
});
$("input[name='"+getName+"[]']:checked").each(function () {
checked.push( $(this).val() );
});
return [filters, checked];
}
and the last to load them:
$(".event_filter").on('click', function() {
var doFilters = getFilters('event_filter');
$('#calendar').fullCalendar( 'removeEvents' );
if (doFilters[0] === doFilters[1]) {
$('#calendar').fullCalendar( 'addEventSource', fcSources.all );
} else {
$.each(doFilters[1], function(myFilter, myVal) {
console.log(myVal);
$('#calendar').fullCalendar( 'addEventSource', fcSources.myVal );
});
}
// $('#calendar').fullCalendar( 'refetchEvents' );
});
Since the sources are all the same place and just different data on the URL, this approach could meet your needs. In the demo it just alerts the URL that is being tried but doesn't actually supply any data...
https://jsfiddle.net/gzbrc2h6/1/
var tournament_url = 'https://www.example.com/'
$('#calendar').fullCalendar({
events: {
url: tournament_url + '/getCalendar/',
data: function() {
var vals = [];
// Are the [ and ] needed in the url? If not, remove them here
// This could (should!) also be set to all input[name='event_filter[]'] val's instead of hard-coded...
var filterVal = '[1,2]';
$('input[name="event_filter[]"]:checked').each(function() {
vals.push($(this).val());
});
if (vals.length) {
filterVal = '[' + vals.join(',') + ']' // Are the [ and ] needed in the url? If not, remove here too
}
return {
typefilter: filterVal
};
},
beforeSend: function(jqXHR, settings) {
alert(unescape(settings.url));
}
}
});
// when they change the checkboxes, refresh calendar
$('input[name="event_filter[]"]').on('change', function() {
$('#calendar').fullCalendar('refetchEvents');
});
Try this!
$('#calendar').fullCalendar({
events: function( start, end, timezone, callback ) {
var checked = [];
$("input[name='event_filter[]']:checked").each(function () {
checked.push( $(this).val() );
});
var tournament_url = 'https://www.example.com';
$.ajax({
url: tournament_url + '/getCalendar/',
data: {typefilter: '['+checked.join(',')+']'},
success: function(events) {
callback(events);
}
});
}
});
$('input[name="event_filter[]"]').on('change', function() {
$('#calendar').fullCalendar('refetchEvents');
});
This works for me.

bootstrap3 pretty-fullcalendar meteor not reactive in blaze

I'm using a bootstrap3 pretty-fullcalendar in a project and pre blaze, when I changed some properties of an event (such as color) it was immediately reflected in the display on the calendar. Now, when I change the attribute, I have to reload the calendar manually to have the change show up.
I'm instantiating the calendar in the template render function as
Template.packLayout.rendered = function(){
$('#calendar').fullCalendar({
//dayClick:function( date, allDay, jsEvent, view ) {
// Requests.insert({title:'Request',start:date,end:date,color:'red',className:'todo'});
// Session.set('lastMod',new Date());
//},
eventClick:function(reqEvent,jsEvent,view){
Session.set('editingReqEvent',reqEvent.id);
Session.set('showEditEvent',true);
},
eventDrop:function(reqEvent){
Requests.update(reqEvent.id, {$set: {start:reqEvent.start,end:reqEvent.end}});
Session.set('lastMod',new Date());
},
events: function(start, end, callback) {
var events = [];
reqEvents = Requests.find();
reqEvents.forEach(function(evt){
event = {id:evt._id,title:evt.title,start:evt.start,end:evt.end,color:evt.color};
events.push(event);
})
callback(events);
},
editable:true,
weekMode: 'liquid'
});
}
Has something changed that would make this happen?
Here is how i managed to get it working:
1) keep your calendar code as per "rendered"
Template.calendar.rendered = function () {
console.log('Calendar - running redered');
Session.set('calendarTemplateRendered', true);
var entries = Calendar.find().fetch(),
$calendar = $('#calendar');
$calendar.html('').fullCalendar({
header: {
left: '',
center: '',
right: ''
},
contentHeight: 1100,
defaultDate: '2014-01-12',
defaultView: 'agendaWeek',
editable: true,
selectable: true,
selectHelper: true,
select: function (start, end) {
var title = prompt('Event Title:');
var eventData;
if (title) {
eventData = {
title: title,
start: start,
end: end
};
$('#calendar').fullCalendar('renderEvent', eventData, true); // stick? = true
}
$('#calendar').fullCalendar('unselect');
},
events: entries
});
Add a autorun:
Deps.autorun(function () {
if (Session.equals('calendarTemplateRendered', false) ||
!calendarSubs.ready() ||
typeof Calendar === 'undefined') {
console.log('exiting because there is no objects to process');
return;
}
console.log('trying to autorun');
var entries = Calendar.find().fetch(),
$calendar = $('#calendar');
$calendar.fullCalendar('removeEvents');
$calendar.fullCalendar('addEventSource', entries);
$calendar.fullCalendar('rerenderEvents');
}
Blaze will do the rest for you - (redraw the UI properly). Now you can just modify your Calendar subscription as you like and it will work perfectly.

Fetching all GoogleCalendar Events before FullCalendar has loaded

I currently am using Adam Shaw's jQuery Calendar 'FullCalendar' and am experiencing significant delays in the calendar rendering. In short, the page appears, 1 second passes, the Calendar pops in, another second passes, and then the events populate the page, here. Is there a way to only fetch a certain number of events behind and before today's date? Or even loading the calendar immediately would be an improvement. I am also using Craig Thompson's qTip2.
Javascript
<script type=text/javascript>
// Setup FullCalendar
jQuery(document).ready
(function() {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
var tooltip = $('<div/>').qtip({
id: 'fullcalendar',
prerender: true,
content: {
text: ' ',
title: {
},
},
events: {
render: function(event, api) {
var elem = api.elements.bgiframe;
}
},
position: {
my: 'bottom center',
at: 'top center',
target: 'event',
viewport: $(window),
adjust: {
mouse: false,
scroll: true,
method: 'shift',
resize: true
}
},
show: {
modal: {
on: false,
blur: true,
stealfocus: false
}
},
hide: false,
style: 'qtip-bootstrap'
}).qtip('api');
$('#fullcalendar').fullCalendar({
eventSources: ["https://www.google.com/calendar/feeds/emailaddresshere/public/basic",
"http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic"],
header: {
left: 'title',
center: '',
right: 'today prev,next'
},
selectable: true,
eventClick: function(data, event, view) {
var content = '<h3>'+data.title+'</h3>' +
'<p><b>Start:</b> '+data.start+'<br />' +
(data.end && '<p><b>End:</b> '+data.end+'</p>' || '');
tooltip.set({
'content.text': content
})
.reposition(event).show(event);
},
dayClick: function() { tooltip.hide() },
eventResizeStart: true,
eventDragStart: false,
viewDisplay: function() { tooltip.hide() }
});
}());
</script>

How to keep data "reactive" when creating an array from a Collection

I am integrating fullCalendar in my meteor application. fullCalendar expects a specific data format. I can create that data from my Collection. However the data is no longer reactive.
What is a way I can make the data I translated from my Collection to an Array "reactive"?
Thanks.
Client html:
<template name="carpool_calendar">
<div id="calendar"></div>
</template>
Client JS:
Template.carpool_calendar.rendered = function () {
//initialize the calendar in this template
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
var calendarEvents = Carpool_Events.find();
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
console.log("Event owner " + ": " + carpool_event.owner);
});
callback(events);
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
weekends: false, // will hide Saturdays and Sundays
editable: true
});
};
Updated Client JS (This is not quite right yet. Its recreating the calendar on every data change...the page gets longer and longer with new calendar instances):
Template.carpool_calendar.rendered = function () {
Meteor.autorun(function() {
//initialize the calendar in this template
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
var calendarEvents = Carpool_Events.find();
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
console.log("Event owner " + ": " + carpool_event.owner);
});
callback(events);
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
weekends: false, // will hide Saturdays and Sundays
editable: true
});
})};
Client JS Fully working "reactive" fullcalendar:
Template.carpool_calendar.rendered = function () {
//initialize the calendar in this template
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
var calendarEvents = Carpool_Events.find();
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
console.log("Event owner " + ": " + carpool_event.owner);
});
callback(events);
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
weekends: false, // will hide Saturdays and Sundays
editable: true
});
Meteor.autorun(function() {
var calendarEvents = Carpool_Events.find();
$('#calendar').fullCalendar('refetchEvents');
});
};
Like TimDog said, you can't give the UI element a reactive array, and let it take care of the rest. But another option is you could use Meteor.autorun so when your collection changes, it can trigger a JS function to make an updated array, thereby making it somewhat reactive.
I'm not sure how to use this calendar exactly, but adding this into your client side code might help.
Meteor.autorun(function() {
calendarEvents = Carpool_Events.find();
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
});
callback(events);
}
});
});
This is part of a bigger question regarding how to properly create UI components for Meteor that ensure reactive data contexts. It's a very good question and one that's been asked before.
The short answer is that there is no standardized framework yet -- like a Meteor.UI smart package. In the interim, however, your best bet is to hack the fullCalendar widget using the {{#each}} helper source as your guide. You'll want to pay attention to how data elements are labeled with Spark:
'each': function (data, options) {
var parentData = this;
if (data && data.length > 0)
return _.map(data, function(x, i) {
// infer a branch key from the data
var branch = (x._id || (typeof x === 'string' ? x : null) ||
Spark.UNIQUE_LABEL);
return Spark.labelBranch(branch, function() {
return options.fn(x);
});
}).join('');
else
return Spark.labelBranch(
'else',
function () {
return options.inverse(parentData);
});
},

Resources