Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
After a weird behaviour of our application (using strophe XMPP and jQuery), we have discovered that the jQuery event loop is synchronous and does not catch exception.
It means that if the first event handler raises an exception, the second one is never called.
$(document).ready(function() {
$(document).bind('foo', onFoo);
$(document).bind('bar', onBar);
$(document).trigger('foo');
$(document).trigger('bar');
});
function onFoo(e) {
console.log('listener onFoo');
throw 'fail onFoo';
}
function onBar(e) {
console.log('listener onBar'); // not called
}
We expected to see two outputs, but the second one : "listener onBar" was never displayed.
See JQuery code, in "trigger" function, there is no try/catch pattern during the loop of the handlers.
while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
event.type = i > 1 ?
bubbleType :
special.bindType || type;
// jQuery handler
handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
... (line 4998 in JQuery 1.10.2)
We have been surprised by this implementation.
In pure JavaScript, all the handlers are called even if one of them crashed: http://jsfiddle.net/bamthomas/kgS7A/2/.
Does someone know why jQuery team does not allow the execution of the next handler even if the previous one crashed ? Why exceptions are not caught?
Why didn't they use JavaScript event handler?
This happens because of this loop taken from the .dispatch source:
while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) {
// Triggered event must either 1) have no namespace, or
// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
if (!event.namespace_re || event.namespace_re.test(handleObj.namespace)) {
event.handleObj = handleObj;
event.data = handleObj.data;
ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler)
.apply(matched.elem, args);
if (ret !== undefined) {
if ((event.result = ret) === false) {
event.preventDefault();
event.stopPropagation();
}
}
}
As you can see, there is no try/catch around .apply.
That's the way it has been for years and years and years.
Even if they wanted, changing it now will break too much existing code. Remember, lots of things in jQuery that seem arbitrary now were born in another time.
You can of course 'fix' this in your own code (wrapping it in a try/catch with error message), but you'll surprise pretty much everyone else.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I have a scripts file which I use for click events that trigger axios or Ajax requests but in some views that button doesn't exist and there is an error in console that says:
Uncaught TypeError: Cannot read property 'addEventListener' of null
How can I prevent this? Do I have to wrap it in an if statement or surely there is a more elegant way?
document.querySelector(".book-now").addEventListener("click", e => {
// declare variables
// send Ajax request
// etc.
You could use a delegate listener instead:
document.addEventListener('click', e => {
if (e.target.matches('.book-now') {
// declare variables
// send Ajax request
// etc.
}
})
If you don't want that (or have to listen to an event that won't bubble) your only option is to check whether the element exists:
let bookNowBtn = document.querySelector(".book-now");
if (bookNowBtn) {
bookNowBtn.addEventListener('click', e => { /*...*/ })
}
You can first check if the element exist
let elem = document.querySelector(".book-now");
if (elem !== null) {
elem.addEventListener("click", e => {
//rest of the code
})
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
While getting used to the concept of promises I have been wondering if elements like HTMLImageElement will have a native promise in future for a 'load' success or failure, similar to the 'load' event which already exists, but with the advantages of being able to be polled after loading?
https://www.w3.org/2001/tag/doc/promises-guide#one-time-events
Promises are definitly a good idea. The problem however is that the DOM has an event model and events and Promises don't really work well together. You can't have a promise for an onclick event for instance (well, you can, but what does it mean?) Some events, like load, may seem to make sense but what if you change the src? You'll get another load event!
Maybe someone is going to have a good idea how to unify these concepts. For now, I think we're stuck with writing code that interfaces between events and Promises.
Not as of HTML5. But I like the concept. I would love to see promise-events in HTML6.
The document you referenced is a guide for when to use promises. So, if you are creating a custom object with events, you might consider implementing a promise interface for your one-time events.
You could easily implement a library to add promise events to DOM elements today.
function loadPromise(image) {
if (image.src && image.complete) {
if (image.naturalWidth > 0) {
return Promise.resolve(image);
}
else {
return Promise.reject(new Error("image failed loading"));
}
}
return new Promise(function(resolve, reject) {
image.addEventListener("load", function(e) {
resolve(image);
}, false);
image.addEventListener("error", function(e) {
reject(new Error("image failed loading"));
}, false);
if (image.src) {
// IE reports image.complete as false when there is an error
var errTest = new Image();
errTest.onerror = function(e) {
reject(new Error("image failed loading"));
};
errTest.src = image.src;
}
});
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm using onclick for an element, but need to pass a callback to it like this:
function cb_func() {
alert("hello world!");
}
function foobar(i, cb) {
do something
if (cb != undefined)
cb();
}
onclick="javascript:foobar(1, cb_func)"
foobar gets called, but my cb_func isn't - in fact when I step in to cb() usinf Firebug, it shows me the HTML for the entire page.
Any ideas how I might achieve this?
Use event delegation:
$(document).on('click', '.dynamicGeneratedEl', function(event){
// do something
cb_func();
});
Where .dynamicGeneratedEl is a suitable selector for your case.
comment the line // do something
function cb_func() {
alert("hello world!");
}
function foobar(i, cb) {
// do something
if (cb != undefined)
cb();
}
Try this:
https://jsfiddle.net/h3ckcgvv/2/
var nextFunction = function() {
// some more stuff happens
}
var processClick = function() {
// some stuff happens
// condition
nextFunction();
}
$('.js-click-me').click(processClick);
The condition could be anything, based on page inspection, javascript variable state, data attributes on the clicked HTML element etc. Much more stable and maintainable than onclick attributes and hardcoding the callback into every call where it's needed.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I want return the var "Page" in a Jquery function :
var Page ;
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
return Page = 'Crea_Bouton';
});
alert(Page); //does not work
But its does not work.
The goal is not to make an alert of the var Page.
In a other page i have : if(Page == 'Crea_Bouton') { //Action }
So, Page must be a global var
Can you help me, please?
There's several issues here. First of all, Page and page are two different variables, but let's assume you've named them the same - your code still won't work.
The problem is, your event handler is not run immediately, it's only run when the double click occurs. Defining page outside of the event doesn't make any sense in this context. What happens is it hits var page; first, then it registers an event (but DOES NOT run the event function), then alerts an empty variable (because the event has not been triggered yet).
When you do trigger the dblclick event, that alert doesn't get executed.
Try this:
var page;
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
page = 'Crea_Bouton';
});
$('#anotherdiv').click(function(){
if(page === 'Crea_Bouton'){
alert("yep!");
}else{
alert("Something else")
}
})
Now, when your #anotherdiv is clicked, it will only alert 'yep!' if the original Montant div has been double clicked first. Otherwise it'll do something else (or nothing at all if you omit the else).
Here's an example jsfiddle:
http://jsfiddle.net/Wb9Ba/
If you click the second button right away, it says "Something else", but if you double click the first button, and then click the second button, it says "yep!"
Use a "callback" function as jQuery does:
function onReturn(page) {
// Process your returned value
if (page == 'Crea_Bouton') {
// Action
alert(page);
}
}
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
var page = 'Crea_Bouton';
onReturn(page);
});
Or process your value inside the dblclick callback:
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
var page = 'Crea_Bouton';
// Do something with my page
if (page == 'Crea_Bouton') {
// Action
alert(page);
}
});
Since the anonymous method inside dblclick is asynchronous, it's impossible to return something.
Instead, you may create a new function:
var page;
$('#Montant').dblclick(function () {
$("#Encadrement_Encaissement_Menu_Creation").show();
display('Crea_Bouton');
});
function display(page) {
alert(page);
// ...
}
Let me just first point out to any IE users right now (this is not a problem in Chrome, Safari or Firefox) hint hint ;)
So... I have a issue with my tooltips in IE, I have a onmouseover listener for all the elements which are to be hoverable and then in my mouseover function I have a very basic cross browser declaration as such...
var event = e || window.event,
el = event.target || event.srcElement;
I've been having issues with the window object not existing in IE or something, this has been a issue after I added a flag to ignore mouseover's from one element mouseover on the way to the tooltip itself (during the time cycle allowed, 300ms). In other words the flag is to ignore mouseovers on route to the tooltip from the original mouseover.
So that logic looks like this...
loadtip.refMouseOver = function (e) {
var event = e || window.event, el = event.target || event.srcElement;
//console.log(window); // <-- throws error in IE (Member not found)
// Reset the lastHoveredRef data.
tipManager.lastHoveredRef = null;
tipManager.lastHoveredRef = [el, event];
// true means there is a tip open still, so if no tip is open.
if (tipManager.tipState !== true) {
tipManager.processTip(el, event);
} else {
return; // do nothing
}
}
The "Member not found" error will occur when I hover from one element quickly to the next in IE with the tooltip still open.
I read about window.open and close stuff with a try catch but I didn't see how that was relevant. Any help is greatly appreciated.
Ok I have found the problem.
To sum it up, basically IE will not pass a event to another function if that function call is within a setTimeout.
So you can trick IE by creating a copy of the event and passing that, here is a example of that...
var eventCopy = {};
for (var i in event) {
eventCopy[i] = event[i];
}
Then just send your function the eventCopy, even though this is a 'total' hack.
setTimeout(function () { yourFunction(eventCopy), yourDelayTime);
And voila it will work.
I should add, that Internet Explorer will merely create a reference to the global window event which is why we need the copy of event. This is because by the time setTimeout calls the function, windows.event has already passed,
Bottom line... don't try to send a event inside a setTimeout because IE won't accept it. This is true for IE 6, 7 & 8 from my testing.
I realize this question/answer is pretty old and seems to be resolved. That being said, I have another alternative I've used to handle a similar -- yet slightly different -- issue with 'Member Not Found' in IE versions prior to MSIE 9. I hope this helps someone out! ...this can also be used to work around issues with Firefox not having window.event.
First I extended jQuery and added a function to get the MSIE version or -1 if the browser is non MSIE. You can do the same or just create a pure JS function to accomplish this. Then create an event override function (it might be necessary to add a global 'event' variable in some cases), that's more of a per individual situation basis. Then override the event in your event handler(s) as needed.
Extending jQuery
// So this will give you the version of IE (or for non IE browser -1)
$.fn.msieVersion = function()
{
if ( navigator.userAgent.toLowerCase().indexOf( 'msie' ) !== -1 ) {
return document.documentMode;
}
return -1;
};
Override the global event
var setEvent = function( evt ) {
// Set the event if MSIE version is >= 9 or is -1 which means it's not IE
if ( $.fn.msieVersion() >= 9 || $.fn.msieVersion === -1 ) {
// NOTE: I have a global 'event' variable I'm using that comes from another previously loaded JS file
// Why? I didn't do it. I'm updating some SUPER old code the best I can. (old enough it has references to Netscape....)
event = evt || window.event;
}
return true;
};
Usage Example
$( 'img.myImageID' ).bind('mouseover mouseout', function ( evt ) {
setEvent( evt ); // Override the event
// DO WORK! ...continue all other awesomeness here!
// Maybe setTimeout(...)
};