In a book, the code for handling mouseDown event is like this:
mousedownhandler: function (ev) {
mouse.down = true;
mouse.downX = mouse.x;
mouse.downY = mouse.y;
ev.originalEvent.preventDefault();
}
So my question is why use ev.originalEvent.preventDefault(); but not ev.preventDefault(); or return false; in this case (HTML5 game)?
jQuery alters the event methods / data in the returned event.
Using event.originalEvent, you're able to retrieve this back.
For example jQuery strips the dataTransfer api for dragged items, using the originalEvent you can use it again.
docs: "jQuery normalizes the following properties for cross-browser consistency ... To access event properties not listed above, use the event.originalEvent object"
In the proposed case it's used to access the preventDefault method (which stops the default action) as it's not included in the jQuery event.
See the definition of preventDefault in jQuery 3.1.1:
jQuery.Event.prototype = {
// ...
preventDefault: function() {
var e = this.originalEvent;
this.isDefaultPrevented = returnTrue;
if ( e && !this.isSimulated ) {
e.preventDefault();
}
},
// ...
};
So basically it will just call native preventDefault. If you are using jQuery I would use its method, it will also update isDefaultPrevented which might be useful if you want to check it (but you could also use native .originalEvent.defaultPrevented).
If you don't care about isDefaultPrevented and know the event has not been simulated by jQuery, then calling native preventDefault might be few milliseconds faster. That's the only potential advantage I can think of, but this definitely won't be a bottleneck.
Returning false in a jQuery event listener is like using both preventDefault and stopPropagation.
I use to know if the event was actually triggered by a physical mouse click. This is useful for avoiding the use of captchas on submit forms.
Related
I'm reusing the native Event class for my own Object Model.
I've found and made use of the Event.stopBubbling property, which does get set to true after Event.stopPropagation() is called. But I can't seem to find any special properties which get modified by Event.stopImmediatePropagation().
How can I tell if an event has had stopImmediatePropagation() called on it?
Are there any properties it modifies, or perhaps some hook I can listen to?
With jQuery:
If you using stopImmediatePropagation of jQuery then i saw the following jQuery code on its GitHub repository.
https://github.com/jquery/jquery/blob/899c56f6ada26821e8af12d9f35fa039100e838e/src/event.js#L594
following is the definition of stopImmediatePropagation there:
stopImmediatePropagation: function() {
var e = this.originalEvent;
this.isImmediatePropagationStopped = returnTrue;
if ( e && !this.isSimulated ) {
e.stopImmediatePropagation();
}
this.stopPropagation();
}
so it looks like Event.isImmediatePropagationStopped is the way to find out what you need.
Without jQuery:
if you are trying to achieve the same without jQuery then i think there is no native way to find out if stopImmediatePropagation is actually called. but the following code can be used to override the original stopImmediatePropagation and get it working like the above.
stopImmediatePropagationOriginal = Event.prototype.stopImmediatePropagation;
Event.prototype.stopImmediatePropagation = function(event){
stopImmediatePropagationOriginal.bind(this).call(event);
this.isImmediatePropagationStopped=true;
};
so with the above code you can use Event.isImmediatePropagationStopped to find out what you need.
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:
I have a setup theoretically like this [see fiddle -> http://jsfiddle.net/GeZyw/] :
var EventTest = function(element) {
this.element = element;
this.element.addEventListener('click', elementClick);
function elementClick() {
var event = document.createEvent('CustomEvent');
event.initEvent('myevent', false, false);
event['xyz']='abc';
event.customData='test';
console.log(event);
this.dispatchEvent(event);
}
}
var element = document.getElementById('test');
var test = new EventTest(element);
$(document).ready(function() {
$("#test").on('myevent', function(e) {
console.log('myevent', e);
});
});
What I want is to create a CustomEvent in pure Javascript, enrich it with some properties and trigger that event so it can be cached also by a library like jQuery.
As you can see in the fiddle, the CustomEvent is triggered well and it is actually populated with custom properties - but when it reaches jQuery on() the custom properties is gone from the first level. My custom properties is now demoted to e.originalEvent.xyz and so on.
That is not very satisfactory. I want at least my own properties to be at the first level.
Also, in a perfect world, I would like to get rid of most of the standard properties in the dispatched event, so it contained (theoretically optimal) :
e = {
xyz : 'abc',
customData : 'test'
}
Is that possible at all? If so, how should I do it?
I have run into the same issue, couple of months ago, the point is:
When an event is received by jQuery, it normalizes the event properties before it dispatches the event to registered event handlers.
and also:
Event handlers won't be receiving the original event. Instead they are getting a new jQuery.Event object with properties copied from the raw HTML event.
Why jQuery does that:
because it can't set properties on a raw HTML event.
I had decided to do the same, I started to do it with a nasty way, and my code ended up so messy, at the end I decided to use jQuery.trigger solution, and pass my event object as the second param, like:
$("#test").bind("myevent", function(e, myeventobj) {
alert(myeventobj.xyz);
});
var myobj = {"xyz":"abc"};
$("#test").trigger("myevent", myobj);
for more info check this link out: .trigger()
When using for events for internet explorer we are currently using statements like this to access or change values:
window.event.cancelBubble = true;
clickX = window.event.screenX;
I was wondering how to do this cross browser or using JQuery?
When you provide a callback to a jquery binding function, it always take as first parameter a event that you should use, even on IE.
Don't use window.event if you're using jQuery.
Note that this is a jQuery wrapped event. For some uses you may need the originalEvent property of the event you get. Here's how you can get both in a callback :
$('#A').click(function(e){
console.log(e); // jquery event
console.log(e.originalEvent); // native event
});
Is there a way to tell the browser to run an addtional java script function on an event such as 'window.resize' instead of overwriting what is already there?
Using jquery's
$(window).resize(<something>);
Seems to replace what is already there. Is there a way to tell it to do something in addition?
Is this a poor design / wrong way to do it?
I wouldn't think that jQuery would break what's there, but you could wrap the functions in a single function:
// if a function already exists...
if( window.onresize ) {
var prev_func = window.onresize; // cache the old function
window.onresize = function( event ) { // new function for resize
prev_func.call( window, event ); // call the old one, setting the
// context (for "strict mode") and
// passing on the event object
// call your code or function
};
}
EDIT: Fixed it to use onresize instead of resize.
EDIT2: Missed one! Fixed.
If you're using jQuery to bind all event handlers, then you're not breaking anything. jQuery supports multiple handlers for same event.
But if other code (not using jQuery) binds to the event, then you'll overwrite handler with your statement. The solution will be: always use jQuery for event binding or try to save old handler (see patrick dw's answer).
See element.addEventListener (element.attachEvent in IE 8 and under):
// Standards
if (window.addEventListener){
window.addEventListener("resize", callOnResize, false);
// IE 8 and under
} else if (window.attachEvent){
window.attachEvent('resize', callOnResize);
}
function callOnResize() {
console.log("resized");
}
Keep in mind this is pure JavaScript—jQuery (and pretty much any big JS library) has a method to handle creating standards and IE handlers without you needing to write each. Still, it's good to know what's happening behind the scenes.
jQuery and all other frameworks supporting custom events attach a function to the event of the elem (or observe it). That function then triggers all functions that have been bound (using bind) for a specific event type.
domelement.addEventListener does not override an other function and your function added can't be removed by other (bad) javascript, except when it would know the exact footprint of your function.