I'm using FullCalendar V4 callback function drop. I try to pass myID which are generated by server to be Calendar event.id, but I do not know how to do. The following is simple code
var calendar = new Calendar(calendarEl, {
drop: function( dropInfo ) {
$.getJSON( url, myParams, function( data ) {
// try to set data.myID to FullCalendar event id
calendarEvent = { id : data.myID };
});
},
eventClick: function( eventClickInfo ) {
var msg = "Are you sure to delete[" + event.title + "]?";
if ( confirm(msg) ) {
// It fails, because I can't get event.id
var params = { method: "deleteEvent", id: event.id };
$.get(url, params, function( data ){
eventClickInfo.event.remove();
});
}
}
});
I have tried to putcalendar.refetchEvents(); into the drop: $.getJSON(function(){}) response block, but FullCalendar makes 2 event in UI. One has balnk attribute, the other has right attribute. If I can eliminate the redundancy, it will be a good solution.
Thanks for ADyson's suggestion. Finally, I used callback function eventReceive solving the problem. The following is my simple code
var calendar = new Calendar(calendarEl, {
eventReceive: function( info ) {
var $draggedEl = $( info.draggedEl );
var params = { method: "insert" };
$.ajaxSetup({ cache: false, async: false});
$.getJSON( myURL, params, function( data ){ // insert information into DB
info.event.setProp( "id", data.id );
});
},
eventClick: function( info ) {
var event = info.event;
var msg = "Are you sure to delete[" + event.title + "]?";
if ( confirm(msg) ) {
var params = { method: "deleteEvent", id: event._def.id };
$.get( myURL, params, function( data ){
event.remove();
});
}
},
});
Related
when i edit a event list, it correctly reload but calendar don't refresh.
if i click in other tab and then return in calendar tab it refresh: problem with bootstrap? This is my function to init calendar
function getCalendar(mydate) {
//Date for the calendar events (dummy data)
var date = new Date()
var d = date.getDate(),
m = date.getMonth(),
y = date.getFullYear()
var calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById('calendar');
var calEv=bindEvents(mydate);
//var calRi=bindResource(mydate);
dCal = new calendar(calendarEl, {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
timeZone: 'UTC',
height: '100%',
contentHeight: 'auto',
initialView: 'dayGridMonth',
themeSystem: 'bootstrap',
locale: 'it',
//Random default events
//events: 'https://fullcalendar.io/demo-events.json',
//events: bindEvents(mydate),
//events: calEv,
//events: evUrl,
events: function(info, successCallback, failureCallback) {
var evUrl = window.apiurl+'/api/anagrafiche/tourfascecalevents/'+id_entita;
$.ajax(evUrl, {
type: 'GET',
cache: false,
}).done(function(dati) {
dbgConsole("render init ev");
dbgConsole(dati);
ev=bindEvents(dati);
dbgConsole(ev);
successCallback(ev);
}).fail(function(x,s,t) {
alert_error(x);
});
},
//resources: bindResource(mydate),
initialDate: dataIni,
editable : true,
selectable: true,
droppable : false, // this allows things to be dropped onto the calendar !!!
dateClick: function(info) {
dbgConsole(info);//event.setProp( name, value )
var cls=[];
var data_fine = moment(info.dateStr, "YYYY-MM-DD").add(gg_viaggio, 'days').format('YYYY-MM-DD');
if ('undefined' == typeof grpSelected || ''==grpSelected) {
// alert('Cancellazione data: ' + info.dateStr + ' !');
var reqUrl = window.apiurl+'/api/anagrafiche/tourfasce/'+id_entita;
$.ajax(reqUrl, {
type: 'DELETE',
cache: false,
data: {
id_gruppo: id_gruppo,
id_entita: id_entita,
MM_delete: 'form_fascedel',
data_inizio: info.dateStr
}
}).done(function(dati) {
window.tables['FasceTable'].setData();
dbgConsole("render");
//$('#h-tab').trigger('click');
//$('#dati-fasce-tab').trigger('click');
dCal.render();
//dCal.updateSize();
}).fail(function(x,s,t) {
alert_error(x);
});
} else {
// alert('Imposta data: ' + info.dateStr + ' in gruppo "'+grpSelected+'" !');
var reqUrl = window.apiurl+'/api/anagrafiche/tourfasce/'+id_entita;
$.ajax(reqUrl, {
type: 'PUT',
cache: false,
data: {
id_gruppo: id_gruppo,
id_entita: id_entita,
MM_update: 'form_fasceupd',
data_inizio: info.dateStr,
nome_periodo: grpSelected,
data_fine: data_fine
}
}).done(function(dati) {
window.tables['FasceTable'].setData();
dbgConsole("render");
//$('#h-tab').trigger('click');
//$('#dati-fasce-tab').trigger('click');
dCal.render();
//dCal.updateSize();
}).fail(function(x,s,t) {
alert_error(x);
});
}
// alert('Gruppo: ' + id_gruppo + ' - Entita: "'+id_entita+ ' - Giorni: "'+gg_viaggio+'" !');
//dCal.setOption('initialDate', '2021-06-01');
//dCal.render();
},
/*
eventClick: function(calEvent, jsEvent, view) {
var testo='';
testo=testo+'Servizio: ' + calEvent.title_serv+'\n';
testo=testo+'Inizio: ' + calEvent.start.format()+'\n';
testo=testo+'Fine: ' + calEvent.end.format()+'\n';
testo=testo+'Descrizione: ' + calEvent.title+'\n';
alert(testo);
}
*/
});
//dCal.render();
dbgConsole("Cal:")
dbgConsole(dCal);//event.setProp( name, value )
}
and this is activation
$('#dati-fasce-tab').on('shown.bs.tab', function (event) {
dCal.render();
})
after 'dateClick' events are modified and reloaded but calendar not update view
P.S.: all events are type 'background'
Already exists any different method to refresh?
We are a problem to refresh on load calendar in hidden area, any idea?
First of all, you need to render the fullcalendar element inside the initialize function.
function getCalendar(mydate) {
...
dCal = new calendar(calendarEl, {
});
dCal.render();
}
After that, you need to use refetchEvents function while an event like changing tab or save an event is firing.
https://fullcalendar.io/docs/Calendar-refetchEvents
dCal.refetchEvents();
You could face into an issue like dCal is undefined, then you need to add some handling like
if (typeof dCal !== 'undefined') {
dCal.refetchEvents();
}
I am struggling with situation of geting events from two different resources. I know that as ajax is asynchronous I cant get more than one callbacks and my code is proving that - By reloading the page I am getting random results from one or other query. But there must be some workaround, right? I just wanna get combined array of both events and vacations so I can pass it to fullcalendar as one instance. Thanks a lot!
var events = [];
var vaca = [];
var now = moment();
var nextMonth = now.clone().add(1, 'month');
$.ajax({
type: "GET",
url: "/home/GetEvents",
success: function (data) {
$.each(data, function (i, v) {
//alert(v.id);
events.push({
title: v.title,
description: "Project Type: " + v.projectType,
start: moment(v.onSite),
end: v.onSiteTill != null ? moment(v.onSiteTill).add('days', 1) : null,
color: v.color,
allDay: true
});
})
GenerateCalendar(events);
},
error: function (error) {
alert('failed');
}
})
$.ajax({
type: "GET",
url: "/home/GetVacations",
success: function (data2) {
$.each(data2, function (i, v) {
//alert(v.who);
vaca.push({
title: v.who,
description: ("Who or what: " + v.who + ". Vacation because " + v.why).link("Vacation/Edit/" + v.id),
start: moment(v.fromWhen),
// add one day due to excluding end date in callendar
end: v.tillWhen != null ? moment(v.tillWhen).add('days', 1) : null,
color: "#cc0000",
allDay: true
});
})
GenerateCalendar(vaca);
},
error: function (error) {
alert('failed');
}
})
You can call next Ajax call from first AJAX call.
Sample Code for Reference:
$.ajax({url: URL, data : {//data
}).done( function( data ) {
// Handles successful responses only
}).fail( function( error) {
console.log( error);
}).then( function( data ) { // Promise finished
$.ajax( { //2nd ajax
url : URL,
data : { DATA }
}).done( function( data ) {
// 2nd call finished
}).fail( function( reason ) {
console.log( error);
});
});
Generate your calendar first then make 2 calls to render the events. You can use the FullCalendar renderEvent or renderEvents to achieve this.
I have created a basic working example here.
I'm using an auto-run block where I re-execute the same mongo with a few session variables ! loop over those doc , construct an array of events then I call the addEventSource and refetchResources function which are pretty expensive computationally ! the fullcalendar becomes slow the more data ! on every action the auto-run block is rerun ! what in your in your opinion can be done to speed things up ? I thought about only re-rendering the delta elements but this doesn't cover the deletion and update .
calendar = $('#calendar').fullCalendar({
schedulerLicenseKey: Meteor.settings.public.fullCalendarLicenseKey,
now: new Date(),
editable: true, // enable draggable events
droppable: true, // this allows things to be dropped onto the calendar
aspectRatio: 1.8,
timezone:'local',
disableDragging: true,
displayEventTime: false,
selectable:true,
allDaySlot:true,
slotDuration:'24:00',
lazyFetching:true,
resourceLabelText: 'Employees',
nextDayThreshold:"12:00",
resources: function(callback) {
var tmp_obj = { usersSorting : { } };
tmp_obj.usersSorting["indexByLocation."+Session.get("locationId")] = 1;
var users = [];
var data = Meteor.users.find({
$or:[
{"profile.showInScheduler":{$exists:false}},
{"profile.showInScheduler":true}
],
assignedTo:{$in:[Session.get("locationId")]},
'locations._id':Session.get("locationId"),
"profile.companyId":Session.get("companyId")
},{sort : tmp_obj.usersSorting});
var arr = data.map(function(c) {
var employeeType = c.userSettings.employeeType;
var type = EmployeeType.findOne({_id:employeeType});
var img = Images.findOne({_id: c.picture});
var imgUrl = img ? img.url() : "/images/default-avatar.png";
c.name = c.name || "";
var totalHoursAllLocation = 0;
var totalHoursCurrentLocation = 0;
return {
id: c._id,
title: "t",
width:"2px"
};
});
callback(arr);
},
drop: function(date, jsEvent, ui, resourceId) {
},
eventResize: function( event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view ) {
},
dayClick: function(date, jsEvent, view,res,res2) {
},
eventClick: function ( event, jsEvent, view ) {
}
}).data().fullCalendar;
/********************* reactive calendar *****************/
this.autorun(function() {
if(Session.get("activeUsers")) {
schedulerSubs = Meteor.subscribe("SchedulesByLocation", Session.get("companyId"), Session.get("locationId"), Session.get("activeUsers"), moment(Session.get("currentDate")).startOf('week').toDate(), moment(Session.get("currentDate")).startOf('week').add(2, "weeks").endOf('isoweek').add(1,"days").toDate());
}
const company = Companies.findOne({_id: Session.get("companyId")});
Session.set("loading", true);
let events = [];
let usersInLocation = Meteor.users.find({
assignedTo: {$in: [Session.get("locationId")]},
'locations._id': Session.get("locationId"),
"profile.companyId": Session.get("companyId")
}).fetch();
let userIds = _.map(usersInLocation, "_id");
userIds.push("temp" + Session.get("companyId") + Session.get("locationId"));
Session.set("activeUsers",userIds);
if(schedulerSubs && schedulerSubs.ready()) {
var data;
SchedulerEvts = Schedules.find({
uid: {$in: userIds},
locationId: Session.get("locationId"),
companyId: Session.get("companyId"),
start: {$gte: moment(Session.get("currentDate")).startOf('week').toDate()},
end: {$lte: moment(Session.get("currentDate")).add(2, "week").endOf('isoweek').toDate()}
}).fetch();
SchedulerEvts.forEach(function (evt) {
var event = null;
var color = "";
var oloc = "";
var attendance = null;
var locationName = "";
var id = evt._id;
event = {
id:id,
type : evt.type,
title: evt.name,
start: evt.start,
end: evt.end,
color:color,
resourceId: evt.uid,
locationName:locationName,
};
events.push(event);
});
if (calendar) {
calendar.removeEvents();
calendar.addEventSource(events);
calendar.refetchResources();
}
}
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.
I have a simple server, you send it a command, it replies back with an \r\n delimited response.
So I tried to get a command( callback ) method on my client. Check out this simplified code snippet:
var net = require('net');
var Client = function() {
this.data = "";
this.stream = net.createConnection(port, host);
this.stream.on('data', function( data ) {
var self = this;
this.data += data;
self.process()
};
this.process = function() {
var _terminator = /^([^\r\n]*\r\n)/;
while( results = _terminator.exec(this.data) ) {
var line = results[1];
this.data = this.data.slice(line.length);
this.emit('response', data);
};
};
this.sendCommand = function( command, callback ) {
var self = this;
var handler = function( data ) {
self.removeListener('response', handler);
callback && callback(data);
}
this.addListener('response', handler);
this.stream.write(command);
};
this.command_1 = function( callback ) {
this.sendCommand( 'test', callback );
};
this.command_2 = function( callback ) {
this.sendCommand( 'test2', callback );
};
}
So I am doing a client.command_1( function() {} ) and then a client.command_2( function() {}) but in the callback of my command_2 I am getting the response from command_1.
Is this the right way to implement such a thing?
When you execute
client.command_1( function() { 1; } );
client.command_2( function() { 2; } );
you add both callbacks as 'result' listeners, and when emit('result') happens for the first time, both callback are called (then first callback removes itself from a list). You need to set callbacks on some kind of request object, not on a client.
simple code on what happens in your client:
var e = new EventEmitter();
e.on('result', function() { console.log(1); });
e.on('result', function() { console.log(2); });
// ...
e.emit('result'); // here we trigger both callbacks which result in printing "1\n2\n"