Reputation: 8279
I have a web page which displays a calendar by FullCalendar
The calendar is being hosted inside a public Salesforce Community page.
I want to be able to create events in the calendar via a mobile device using touch
and drag
.
Both Salesforce Communities and FullCalendar support mobile devices.
And FullCalendar has touch support
But when I access the community page using a mobile device I am unable to use the touch
and drag
to create a calendar entry.
There are touch
event handlers created by the Salesforce community page/framework:
document
for touchstart
and touchend
and touchcancel
window
for touchmove
Which seem to override the FullCalendar touch
events.
Here is an example calendar for debugging:
How can I remove the touch
event handlers on the document
and window
?
I've tried adding:
document.addEventListener("touchstart", function (event) {
event.preventDefault();
console.log("touchstart: event.preventDefault()");
}, false);
document.addEventListener("touchend", function (event) {
event.preventDefault();
console.log("touchend: event.preventDefault()");
}, false);
document.addEventListener("touchcancel", function (event) {
event.preventDefault();
console.log("touchcancel: event.preventDefault()");
}, false);
window.addEventListener("touchmove", function (event) {
event.preventDefault();
console.log("touchmove: event.preventDefault()");
}, false);
But I just got this error in the console:
[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive.
And none of the calendar buttons worked anymore.
Upvotes: 2
Views: 4583
Reputation: 35
Maybe try forwarding the "SFDC" touch
event to the FullCalendar event
document.addEventListener("touchstart", function (event) {
myFullCalendarEvent.OnTouch(event);
}, false);
Though generally, I have never tried to remove events like this when I still expect it to work at a lower level... Given you are having problems with your current approach, this is where I would go next..
Upvotes: 0
Reputation: 25547
Not sure exactly what problem you (the OP) are having. https://sfse-developer-edition.eu16.force.com/FullCalendar/s/ mostly works for me when viewed on an iPad running Safari. I found some bugs (see below), but maybe you are just not touching long enough.
According to the FullCalendar documentation: "On a touch device, for the user to begin drag-n-dropping events, they must first tap-and-hold on the event in order to “select” it!" (emphasis in original). You can configure the delay using longPressDelay
.
Whatever problem you are having, I'd say it's highly unlikely that the best fix involves removing event handlers. More likely you will find the answer in the documentation for SalesForce Community about how to integrate other JavaScript packages into a page.
For example, I found a bug in this bit of code, which Chrome says is from https://sfse-developer-edition.eu16.force.com/FullCalendar/s/components/c/FullCalendar.js
but does not actually seem to come from that URL. Anyway, given the console.log('loadCalendar')
line, I'm guessing you, the OP, wrote it.
"helper":{
"loadCalendar":function(component) {
console.log('loadCalendar');
var params;
var self = this;
var calendar = component.find('calendar').getElement();
$(calendar).fullCalendar('destroy');
$(calendar).fullCalendar({
header: {
left: 'prev,next',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
schedulerLicenseKey: '0537034756-fcs-1530699190',
defaultView: 'agendaWeek',
// <snip> bunch of stuff omitted for brevity
select: function (starts, ends) {
params.starts = starts.format('x');
params.ends = ends.format('x');
},
// <snip> lots more stuff omitted
The problem here is that params
is never initialized, so params.starts
is an invalid reference that throws an uncaught TypeError
. This can probably be solved by replacing var params;
with var params = {};
but I can't be sure.
Upvotes: 1
Reputation: 1951
The EventTarget.removeEventListener() method removes from the EventTarget an event listener previously registered with EventTarget.addEventListener(). The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal.
More on https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
Upvotes: 0
Reputation: 14155
You can not remove the listener if you add new listener. All listeners will be added in the queue. You can see it for example here:
var listenerLoad = function(e){console.log(1)};
window.addEventListener('load', listenerLoad, false);
window.addEventListener('load', listenerLoad, true);
window.addEventListener('load', function(e){console.log(3)}, false);
window.onload = function(e){console.log(4)};
But you can remove the listener if you use the appropriate function for this. You have to use the function EventTarget.removeEventListener()
. Read this documentation carefully before. The parameters have to be the same like in addEventListener()
by initialization from this events. And the pointers to the listerners should be the same like in addEventListener()
. For example if you they have the pointers to the listerners like:
var listenerTouchStart = function(e){/**/},
listenerTouchEnd = function(e){/**/},
listenerTouchCancel = function(e){/**/},
listenerTouchMove = function(e){/**/};
then you can delete the listeners like follows:
document.removeEventListener('touchstart', listenerTouchStart, false);
document.removeEventListener('touchend', listenerTouchEnd, false);
document.removeEventListener('touchcancel', listenerTouchCancel, false);
window.removeEventListener('touchmove', listenerTouchMove, false);
But do not forget that window.removeEventListener('touchmove', listenerTouchMove, false);
and window.removeEventListener('touchmove', listenerTouchMove, true);
are not the same. If they add the listener with false
and you try to remove it with true
then it will not work. Be careful!
If you want to find the listener function names then you have 3 ways:
getEventListeners(Object);
. For example for our window in the first example you will have an output like this:And if the listener was added with anonymous function then it does not have a name.
// THIS SNIPPET SHOULD NOTHING DO.
// IT IS ONLY TO HIDE THIS LONG CODE
function DO_NOT_COPY_THIS_LINE() //<-DO NOT COPY THIS LINE
{
//////////////////////////////
//ListenerTracker Script START
//////////////////////////////
var ListenerTracker = new function()
{
var is_active=false;
// listener tracking datas
var _elements_ =[];
var _listeners_ =[];
this.init=function(){
if(!is_active){//avoid duplicate call
intercep_events_listeners();
}
is_active=true;
};
// register individual element an returns its corresponding listeners
var register_element = function(element){
if(_elements_.indexOf(element)==-1){
// NB : split by useCapture to make listener easier to find when removing
var elt_listeners=[{/*useCapture=false*/},{/*useCapture=true*/}];
_elements_.push(element);
_listeners_.push(elt_listeners);
}
return _listeners_[_elements_.indexOf(element)];
};
var intercep_events_listeners = function(){
// backup overrided methods
var _super_={
"addEventListener" : HTMLElement.prototype.addEventListener,
"removeEventListener" : HTMLElement.prototype.removeEventListener
};
Element.prototype["addEventListener"] = function(type, listener, useCapture){
var listeners=register_element(this);
// add event before to avoid registering if an error is thrown
_super_["addEventListener"].apply(this,arguments);
// adapt to 'elt_listeners' index
useCapture=useCapture?1:0;
if(!listeners[useCapture][type])listeners[useCapture][type]=[];
listeners[useCapture][type].push(listener);
};
Element.prototype["removeEventListener"] = function(type, listener, useCapture){
var listeners=register_element(this);
// add event before to avoid registering if an error is thrown
_super_["removeEventListener"].apply(this,arguments);
// adapt to 'elt_listeners' index
useCapture=useCapture?1:0;
if(!listeners[useCapture][type])return;
var lid = listeners[useCapture][type].indexOf(listener);
if(lid>-1)listeners[useCapture][type].splice(lid,1);
};
Element.prototype["getEventListeners"] = function(type){
var listeners=register_element(this);
// convert to listener datas list
var result=[];
for(var useCapture=0,list;list=listeners[useCapture];useCapture++){
if(typeof(type)=="string"){// filtered by type
if(list[type]){
for(var id in list[type]){
result.push({"type":type,"listener":list[type][id],"useCapture":!!useCapture});
}
}
}else{// all
for(var _type in list){
for(var id in list[_type]){
result.push({"type":_type,"listener":list[_type][id],"useCapture":!!useCapture});
}
}
}
}
return result;
};
};
}();
ListenerTracker.init();
//////////////////////////////
//ListenerTracker Script END
//////////////////////////////
}
I have found this ListenerTracker script here. With this script you will get even anonymous listeners, but you have to add it before they add some listeners in the code.
Good luck!
Upvotes: 9