Here is my code:
var e = jQuery.Event( "keydown", { keyCode: 64 } );
There is data being attached to the event in the second parameter. Now I have seem that kind of syntax in a lot of plugins and was wondering, what's the use of attaching arbitrary data to a $.event/custom event?
I have seen the jQuery docs event object and also trigger.
I am wondering, if the only usage of attaching data to a event is as follows:
var e = jQuery.Event( "keydown", { keyCode: 64 } );
// above is the line I am having difficulty understanding
// the usage of arbitrary data with the $.event is quite
// elusive to a novice developer like me
$(window).on('keydown' , function(e){
console.log('key 64 pressed');
});
press = function(){
$(window).trigger(e);
}
setTimeout(function(){
press();
}, 2000);
JS Fiddle here
I.e. triggering an event on a specific key or a specific element, I mean is this the only use of attaching arbitrary data to an $.event?
Sometimes you are using your code that behaves in some way depending on the interaction.
In your example, you are "manually" triggering the keydown event on that input in order to "trigger" the event-listeners listening to this event.
Probably on this example you have a idle logout system going on and you activated something to keep the session alive on your UI as long as needed.
The other day I had to use something similar in order to keep a dropdown open in a third party plugin that was closing a drop down on selection after a search.
Related
I have already looked at these questions:
How to find event listeners on a DOM node when debugging or from the JavaScript code?
can I programmatically examine and modify Javascript event handlers on html elements?
How to debug JavaScript/jQuery event bindings with Firebug (or similar tool)
however none of them answers how to get a list of event listeners attached to a node using addEventListener, without modifying the addEventListener prototype before the event listeners are created.
VisualEvent doesn't display all event listener (iphone specific ones) and I want to do this (somewhat) programmatically.
Chrome DevTools, Safari Inspector and Firebug support getEventListeners(node).
You can't.
The only way to get a list of all event listeners attached to a node is to intercept the listener attachment call.
DOM4 addEventListener
Says
Append an event listener to the associated list of event listeners with type set to type, listener set to listener, and capture set to capture, unless there already is an event listener in that list with the same type, listener, and capture.
Meaning that an event listener is added to the "list of event listeners". That's all. There is no notion of what this list should be nor how you should access it.
Since there is no native way to do this ,Here is the less intrusive solution i found (dont add any 'old' prototype methods):
var ListenerTracker=new function(){
var targets=[];
// listener tracking datas
var _elements_ =[];
var _listeners_ =[];
this.init=function(){
this.listen(Element,window);
};
this.listen=function(){
for(var i=0;i<arguments.length;i++){
if(targets.indexOf(arguments[i])===-1){
targets.push(arguments[i]);//avoid duplicate call
intercep_events_listeners(arguments[i]);
}
}
};
// 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(target){
var _target=target;
if(target.prototype)_target=target.prototype;
if(_target.getEventListeners)return;
if(typeof(_target.addEventListener)!=='function'||typeof(_target.removeEventListener)!=='function'){
console.log('target=',target);
throw('\nListenerTracker Error:\nUnwrappable target.');
}
// backup overrided methods
var _super_={
"addEventListener" : _target.addEventListener,
"removeEventListener" : _target.removeEventListener
};
_target["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
var uc=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
if(!listeners[uc][type])listeners[uc][type]=[];
listeners[uc][type].push({cb:listener,args:arguments});
};
_target["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=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
if(!listeners[useCapture][type])return;
var lid = listeners[useCapture][type].findIndex(obj=>obj.cb===listener);
if(lid>-1)listeners[useCapture][type].splice(lid,1);
};
_target["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].cb,
"args":list[type][id].args,
"useCapture":!!useCapture
});
}
}
}else{// all
for(var _type in list){
for(var id in list[_type]){
result.push({
"type":_type,
"listener":list[_type][id].cb,
"args":list[_type][id].args,
"useCapture":!!useCapture
});
}
}
}
}
return result;
};
};
}();
ListenerTracker.init();
EDIT
Suggestion from #mplungjan: modified to listen to wrappable targets (singleton|constructor). 'init' tracks Element and window .
exemple with other wrappable target:
ListenerTracker.listen(XMLHttpRequest);
Suggestion from #kodfire : You may get optionals arguments with the args property.
I can't find a way to do this with code, but in stock Firefox 64, events are listed next to each HTML entity in the Developer Tools Inspector as noted on MDN's Examine Event Listeners page and as demonstrated in this image:
You can obtain all jQuery events using $._data($('[selector]')[0],'events'); change [selector] to what you need.
There is a plugin that gather all events attached by jQuery called eventsReport.
Also i write my own plugin that do this with better formatting.
But anyway it seems we can't gather events added by addEventListener method. May be we can wrap addEventListener call to store events added after our wrap call.
It seems the best way to see events added to an element with dev tools.
But you will not see delegated events there. So there we need jQuery eventsReport.
UPDATE: NOW We CAN see events added by addEventListener method SEE RIGHT ANSWER TO THIS QUESTION.
What is the best way to distinguish events in JavaScript.
Actually there are two points I am interested in. The first one is are there something like id in event (it would be very useful foe debugging purposes). And another point are there better ways to distinguish mousedown and mousedown&touchstart events.
Let me tell you my story. I met the problem that if you add two dom events to a node with triggers mousedown and touchstart, then on mobile devices both mousedown and touchstart run.
The first solution I found was to run
event.preventDefault();
event.stopPropagation();
at the beginning of each listener function.
But then I found out an event delegation pattern and started to work with analytics, all that disallowed to use the previous approach, so I come up with the following solution:
let lastEvent = null;
const specificListener = function(e) {
if (lastEvent === e) {
return; //already run the code due to another listener
}
/*
logic goes here
*/
lastEvent = e;
};
And now I am interested whether or not it is possible to compare events in a different way (different from event1 === event2, hope to find out about something like event1.id === event2.id)?
Thank you.
Instead of trying to differentiate the events, just subscribe to mousedown only, as it is fired anyway. That's the most simple solution I'd say.
Or, you could try to detect which event system is supported and only subscribe to the appropriate one:
var eventType = document.ontouchstart != null ? 'touchstart' : 'mousedown';
document.addEventListener(eventType, (e) => { ... });
A third solution (possibly) would be to use PointerEvents only, but that depends on the platforms you need to support.
https://caniuse.com/#search=pointer%20events
If you for sure cannot use one of these approaches: Every event should have a timestamp property (not sure if it is named that way), maybe you can find a way to distinguish two events with it.
I'm currently attempting to test some code that uses drag-and-drop. I found some other questions that were kinda related to this, but they were way too specific to help me, or not related enough.
This being a test, I'm struggling on trying to automatically execute code inside a .on('drop',function(e){....} event. The main issue is not that I can't run the code inside, but it's that I can't transfer the dataTransfer property, and I can't seem to fake it because it's read-only. Is there anyway to fake the dataTransfer property or otherwise get around it?
I came up with this JSFiddle that serves as a template of what I'm trying to do: https://jsfiddle.net/gnq50hsp/53/
Essentially if you are able to explain to me (if this is at all possible) how I can possibly fake the dataTransfer property, I should be all set.
Side notes:
I'm totally open to other ways of somehow getting inside that code, like for example, maybe its possible to trigger the event and pass in a fake event object with a fake dataTransfer object.
To see the drag-drop behavior, change the JavaScript load type from no-wrap head to on-Load, then you should see what I'm trying to simulate.
Important to note that I cannot modify any of the code inside the event handlers, only inside the outside function
Using Karma/Jasmine so use of those tools are also possible like spies
Also, I'm using Chrome.
Thanks in advance, and let me know for any questions/clarifications!
You should be able to override pretty much everything you want using Object.defineProperty. Depending on what you want to test it can be very simple or very complex. Faking the dataTransfer can be a bit tricky, since there's a lot of restrictions and behaviors linked to it, but if you simply want to test the drop function, it's fairly easy.
Here's a way, this should give you some ideas as to how to fake some events and data:
//Event stuff
var target = $('#target');
var test = $('#test');
test.on('dragstart', function(e) {
e.originalEvent.dataTransfer.setData("text/plain", "test");
});
target.on('dragover', function(e) {
//e.dataTransfer.setData('test');
e.preventDefault();
e.stopPropagation();
});
target.on('dragenter', function(e) {
e.preventDefault();
e.stopPropagation();
});
//What I want to simulate:
target.on('drop', function(e) {
console.log(e)
//Issue is that I can't properly override the dataTransfer property, since its read-only
document.getElementById('dataTransferDisplay').innerHTML = e.originalEvent.dataTransfer.getData("text");
});
function simulateDrop() {
// You'll need the original event
var fakeOriginalEvent = new DragEvent('drop');
// Using defineProperty you can override dataTransfer property.
// The original property works with a getter and a setter,
// so assigning it won't work. You need Object.defineProperty.
Object.defineProperty(fakeOriginalEvent.constructor.prototype, 'dataTransfer', {
value: {}
});
// Once dataTransfer is overridden, you can define getData.
fakeOriginalEvent.dataTransfer.getData = function() {
return 'test'
};
// TO have the same behavior, you need a jquery Event with an original event
var fakeJqueryEvent = $.Event('drop', {
originalEvent: fakeOriginalEvent
});
target.trigger(fakeJqueryEvent)
}
https://jsfiddle.net/0tbp4wmk/1/
As per jsfiddel link you want to achieve drag and drop feature. jQuery Draggable UI already provides this feature why you can not use that?
For create custom event on your way you have to follow two alternative ways
$('your selector').on( "myCustomEvent", {
foo: "bar"
}, function( event, arg1, arg2 ) {
console.log( event.data.foo ); // "bar"
console.log( arg1 ); // "bim"
console.log( arg2 ); // "baz"
});
$( document ).trigger( "myCustomEvent", [ "bim", "baz" ] );
On above example
In the world of custom events, there are two important jQuery methods: .on() and .trigger(). In the Events chapter, we saw how to use these methods for working with user events; for this chapter, it's important to remember two things:
.on() method takes an event type and an event handling function as arguments. Optionally, it can also receive event-related data as its second argument, pushing the event handling function to the third argument. Any data that is passed will be available to the event handling function in the data property of the event object. The event handling function always receives the event object as its first argument.
.trigger() method takes an event type as its argument. Optionally, it can also take an array of values. These values will be passed to the event handling function as arguments after the event object.
Here is an example of the usage of .on() and .trigger() that uses custom data in both cases:
OR
jQuery.event.special.multiclick = {
delegateType: "click",
bindType: "click",
handle: function( event ) {
var handleObj = event.handleObj;
var targetData = jQuery.data( event.target );
var ret = null;
// If a multiple of the click count, run the handler
targetData.clicks = ( targetData.clicks || 0 ) + 1;
if ( targetData.clicks % event.data.clicks === 0 ) {
event.type = handleObj.origType;
ret = handleObj.handler.apply( this, arguments );
event.type = handleObj.type;
return ret;
}
}
};
// Sample usage
$( "p" ).on( "multiclick", {
clicks: 3
}, function( event ) {
alert( "clicked 3 times" );
});
On above example
This multiclick special event maps itself into a standard click event, but uses a handle hook so that it can monitor the event and only deliver it when the user clicks on the element a multiple of the number of times specified during event binding.
The hook stores the current click count in the data object, so multiclick handlers on different elements don't interfere with each other. It changes the event type to the original multiclick type before calling the handler and restores it to the mapped "click" type before returning:
there's not a lot of documentation for this but I'm hoping someone can help me.
I'm using the QRTEngine provided by the folks over at http://qrtengine.com/ for Qualtrics (http://www.qualtrics.com/) - a survey tool.
I have managed to set up a 'agree/disagree' survey quite easily (user presses the key 'z' for disagree and 'm' for agree)
The problem is that I need this to work on mobile too. Now I've tried the following:
var j = jQuery.noConflict();
(function( j ) {
j(function() {
// More code using $ as alias to jQuery
var e = j.Event("keyup");
e.which = 77; // # Some key code value
j( ".agree" ).bind( "click", function( event ) {
j(this).trigger(e);
alert(e.which);
});
});
})(j);
Which executes the alert but doesn't seem to simulate the keypress. I don't think there's anything wrong with my code, but I'm wondering if I'm missing something in regard to the QRTEngine I'm using.
Any help (ANY) would be appreciated.
Thanks
$ is the alias for the Prototype framework in Qualtrics. If you want use an alias for jQuery you need to make it something else like $j:
var $j = jQuery.noConflict();
EDIT: Maybe this is your problem...from http://bililite.com/blog/2015/01/14/rethinking-fn-sendkeys/ :
"Modern browsers won't let synthetic events (triggered with dispatchEvent) execute their default actions (meaning the action that would occur if the event was triggered by a user action). The Event object has a read-only field called isTrusted that is false for anything but unmodified user-initiated events. These are called "trusted events", and I understand the justification, but they go too far. It makes it impossible to implement a virtual keyboard, since triggering keydown or keypress events aren't trusted and won't insert the character (the default action)."
Check out the link referenced above for a potential solution.
I am trying to figure out how to programmatically add an event handler to a JavaScript object. More specifically, I am trying to add an event handler to the onunload event of a window object. I am trying it like so with out any luck:
var url = "www.somelocation.com";
var specs = "location=0,menubar=0,status=0,titlebar=0,toolbar=0";
var dialogWindow = window.open(url, "dialog", specs, true);
dialogWindow.onunload += myEventHandler;
function myEventHandler(e)
{
// Do stuff
}
I'm guessing my syntax is incorrect. However, I cannot seem to find any documentation regarding this. Can someone please help me?
dialogWindow.onunload += myEventHandler is incorrect. This should really be:
dialogWindow.unload = myEventHandler;
Or to preserve the existing handlers:
var oldHandler = dialogWindow.unload;
dialogWindow.unload = function (e)
{
if (oldHandler) { oldHandler(e); }
myEventHandler(e);
}
And, of course, use JQuery.
Javascript only manages objects. The HTML DOM elements including HTML5 are objects, we can categorize them as follows:
The Window object that has all the events
The IFRAME object which is as complete as Window (this is why it is used by Youtube)
DOM objects that only have management events, click, mouseup, mouseDown ... as well as their own events (audio, video, DIV BLOCK), etc.
Building JAVASCRIPT objects is a bit like Visual Basic or C ++.
Events are easy to manage, we can mix the events of smartphones and computers. To ensure support for old browsers SAFARI, IE, just avoid using certain keywords like (LET, =>, or values in the parameters of functions like X = 1).
Event Management:
var mouseup = (!('ontouchstart' in document.documentElement))? 'mouseup':'touchend';
var winresize = (!('ontouchstart' in document.documentElement))? 'resize':'orientationchange';
var mouseover = (!('ontouchstart' in document.documentElement))? 'mouseover':'touchstart';
var mouseout = (!('ontouchstart' in document.documentElement))? 'mouseout':'touchend';
To ensure compatibility:
var Event_mouseup = function (e)(
Code mouseup.......
};
if(object.addEventListener){
object.addEventListener(mouseup,Event_mouseup,{passive:true}); //passive true not return event
}else if(object.attachEvent){
object.attachEvent(mouseup,Event_mouseup);
}else{
object['on'+mouseup]=Event_mouseup;
};
The Window object works exactly the same.
The event load is really special in an HTML page.
The objects that handle this event are objects that load data like IMG, VIDEO, AUDIO, etc.
In general, when an object has a load event it also has an error loading event.
To understand the DOM and the browser, you have to compare it to a C ++ window for example.
Window
----------------------- event Load
-------- Object 1 HTML DOM
--------- event1 Object
--------- event2 Object
-------- Object 2 HTML DOM
--------- event1 Object
--------- event2 Object
---------------------- event unload
Window