Why jQuery's triggerHandler() doesn't prevent inline events? - javascript

I've made this test code for the question: https://jsfiddle.net/5phqm/1/
As far as I understand, if jQuery's triggerHandler() prevents default browser behavior, then native JavaScript events will not be triggered and handled (and it's true for addEventListener() in my code), but inline event, added through tag's attribute onclick="" will be triggered anyway! Why it happens? Am I misunderstanding something about events triggering in browser?

It can be confirmed that inline handlers are run because it is explicitly coded:
handle = ontype && cur[ ontype ];
if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
event.preventDefault();
}
where ontype is in this case "onclick". So it is fetching the onclick property of the element and then executing it. This piece of code is always called, regardless of .trigger/.triggerHandler.
Native actions however, like elem.click(), are only executed inside an if block:
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
// ...
elem[ type ]();
where onlyHandlers is true for triggerHandle and false for .trigger, and therefore triggerHandler does not execute e.g. elem.click() (whereas .trigger does). As such, the native action is prevented.
So inline handlers and native actions are separate things and are also handled separately. Only native actions are prevented by .triggerHandler.

I think (but it's a guess, i gave a brief look at jQuery source code and this might be totally wrong) that jQuery retrieves the events attached to elements in jQuery.trigger.event by calling something like
$(elem).data("events");
and then decides if to fire/stop them. Inline events can't be collected this way and so they can't be stopped.

Related

How to make this execute only once keyup [duplicate]

I have multiple images on my page. To detect broken images , I used this found on SO.
$('.imgRot').one('error',function(){
$(this).attr('src','broken.png');
});
This works fine on the first image which I understand. But when I change this to
$('.imgRot').on('error',function(){
$(this).attr('src','broken.png');
});
it does not work on any of the images . Could someone tell me why ?
Community wiki: This generic answer does not contribute to the question OP posted but relative to the title.
The concept of one() and on() can be explained with the below code.
one() function is automatically moved to off state after first instance of occurance.
on() is identical to one() but it needs to be manually put to off state otherwise the number of instances has no limit.
var i = 1;
$('.one').one('click', function() {
$(this).text('I am clickable only once: ' + i);
i++;
});
var j = 1;
$('.multiple').on('click', function() {
$(this).text('I was clicked ' + j + ' times');
j++;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one">Click me</div>
<div class="multiple">Click me</div>
If you look at the source code for .one() in jQuery 1.7, it just calls .on() internally except that after the event fires, it removes the event handler. So, there should be no difference in your case because error is an event that should only happen once per object anyway.
So, there must be something else going on in your code like maybe the image objects haven't been loaded into the DOM yet when you run this code or something like that.
If you were trying to use delegated event handling to do this (which your example does not show), then you may run into issues where the 'error' event doesn't propagate.
It may also be that your code has timing issues due to caching. Trying to install these types of error handlers on images that are already in the DOM is a race condition. You're trying to get the error handler installed before it gets called, but the image has already started loading and the event might have already fired before you get the event handler installed. Subsequent page loads (after the first) may have cached other page elements or DNS references so it may get to the error handler quicker and perhaps even before your JS can run and install the error handlers.
I know this is an issue with browser caching and the onload event. You can only reliably get the onload event if you attach the event handler either in the embedded HTML (so it's there when the <img> tag is first parsed or if you attach it before the .src property has been set (if creating the image programmatically). That would suggest that you can't reliably set error handlers the way you are doing for images that are in the page HTML.
My suggestion would be this:
Don't try to install error handlers like this after the images are in the DOM.
If you assign them on programmatically generating images, then assign the event handlers before .src is assigned.
If you need these on images in the page's HTML, then you will have to put the event handlers in the HTML with something like <img src="xxx" onerror="yourErrorFunc(this)"> because that's the only way to guarantee that the handlers are installed before the event can occur.
jQuery will reuse the "on" method for the "one". Following is the internal code of jQuery where they'll be passing hardcoded value "1" to the function of jQuery.on() They'll turn off the triggered event further on the element using jQuery.off()
on:function( types, selector, data, fn, one ) {
if ( one === 1 ) {
origFn = fn;
fn = function( event ) {
jQuery().off( event );
return origFn.apply( this, arguments );
};
}
off:function(types, selector, data, fn){
on(types, selector, data, fn, 1);
}
So, in your case "error" is the event type triggered on the first image and when the jQuery.one() method called this event got turned off and then its not triggered for further on the $('.imgRot') elements

Calling an Onclick() function without clicking?

A websites Button isn't rendering on my browser. I know it's there, when I'm in the view source I still see the button, and the onclick function. Can I still call this function by passing the url the function? Or in the console?
Even if it's not an onclick, is it possible to call functions by either URL or Console?
You can click any DOM element by selecting it and calling the click() function.
document.getElementById("yourElementId").click();
Works with Jquery as well.
$(selector).click();
To accomplish this, you can use the following line:
document.getElementById("element_id").click()
According to MDN, this simulates a full click on the element, including all it entails:
When click is used with elements that support it (e.g. one of the types listed above), it also fires the element's click event which will bubble up to elements higher up the document tree (or event chain) and fire their click events too. However, bubbling of a click event will not cause an element to initiate navigation as if a real mouse-click had been received.
Alternatively, you can use jQuery to accomplish the same thing:
$("#trigger").click();
Here is the simplest way:
function fireClick(node){
if ( document.createEvent ) {
var evt = document.createEvent('MouseEvents');
evt.initEvent('click', true, false);
node.dispatchEvent(evt);
} else if( document.createEventObject ) {
node.fireEvent('onclick') ;
} else if (typeof node.onclick == 'function' ) {
node.onclick();
}
}
So you can trigger the click event for an element like below:
fireClick(document.getElementById('id'));
Reference from here.

Creating a javascript function to make a button click

I want to make it so that when a track completes playing it automatically calls a javascript function which clicks the next track button so that the playlist continues to play. So far i have:
function next() {
$("#nextTrack").click();
}
But that doesn't seem to do anything when it is called, anyone know where i am going wrong?
The way to trigger the click event on the DOM element itself is with:
$("#nextTrack")[0].click();
This gets the first (only) DOM element matched (removes it from the jQuery wrapper) and calls the native click method.
The only reasoning I can provide for this is because trigger doesn't (or hasn't, in past versions) attempted to call the native method. I swear in the most recent version, I can use .trigger("click") (same as .click()) and it will effectively click the element...executing native any click handlers and jQuery handlers as well.
trigger is tricky because jQuery stores any event handlers bound with jQuery.on, jQuery.bind, etc. in a special place. When the native event is fired, or .trigger("event_name") is used, all those special handlers are executed. But for some reason, the native event isn't always triggered (as you seem to have found out). I'm not sure if it's because of the version of jQuery or the event type.
UPDATE:
The reason this is happening is because jQuery treats <a> specially when using .trigger("event_name"), specifically for the click event.
After blabbering with the stuff above, I decided to look into the jQuery source code for trigger. In the end, the native DOM method is called, with elem[ type ]();. But it only gets to this point under certain conditions...these are the conditions (among other nested if statements):
if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
And I'm guessing that specifically, the part !(type === "click" && jQuery.nodeName( elem, "a" )) is what prevents it in your case, because the element you're targeting is <a>, and it's the click event.
DEMO: Here's basically just something mimicking your code in a simpler fashion: http://jsfiddle.net/EjVMY/ - notice how the initial console.log on load doesn't execute (because of the trigger). But as soon as you actually click on the event, the console.log does execute. I found that replacing the <a> with a <div> changes the behavior - it logs on load.
Of course, if I had just Googled it in the first place, I would've found: trigger a click on a anchor link

jQuery programmatically trigger events

What all events can be triggered programmatically using jQuery? Also is there any important differences to be remembered when one is doing event triggering using jQuery Vs a natural way of it being triggered?
Every event can be programmatically fired, just use the callback-less version of it.
Example:
$('#button').click(function() { alert('event hanlder'); });
$('#button').click(); // generate the event
About your second question, there should be no difference between the native and jQuery event handlers.
One thing that is neat though is that jQuery binds this to the element that received the event, inside the callback (this doesn't happen in native event handlers):
$('#button').click(function() { alert(this); }); // here 'this' == document.getElementById('button');
Warning: the element referenced by this is not "jQuery augmented". If you want to traverse or modify it with jQuery goodness you'll have to do something like var $this = $(this);
You should know the differences between trigger and triggerHandler in jQuery.
trigger
trigger attempts to replicate the natural event as best as it can. The event handler for the event being triggered get's executed, but the default browser actions will not always be replicated exactly. For example $('a#link).trigger('click'); will execute the javascript function bound to the links click event handler, but will not redirect the browser to the href of the anchor, like a normal click would. EX: http://jsfiddle.net/AxFkD/
All the short forms of the trigger call behave exactly like trigger IE. click(), mouseup(), keydown(), etc
triggerHandler
triggerHandler prevents bubbling up ( EX. http://jsfiddle.net/LmqsS/ ), it avoids default browser behaviour and just executes the events callback, and it returns the return value of the event handler instead of a jQUery object for chaining.
You should also be aware that trigger affects all elements matched by a selector, but triggerHandler only affects the first one EX: http://jsfiddle.net/jvnyS/
You can trigger any event programmatically. But most of the events cannot be simulated as the natural event using programmatic triggers.
//to trigger a click event on a button
$("buttonSelector").trigger("click");
First, for obvious reasons, you cannot trigger the ready event.
That said, events raised by trigger() behave the same way as if they were triggered by the user. In particular, the event handlers are called in the same order.
The only difference I know of is that triggered events did not bubble up the DOM tree in older versions of jQuery (that behavior was fixed in version 1.3).

Simulating a click in jQuery/JavaScript on a link

I want to simulate a click on any link on a page using JavaScript. If that link has some function binded to its 'onclick' event (by any other JS I don't have any control over), then that function must be called otherwise the link should behave in the normal manner and open a new page.
I am not sure that just checking the value of the 'onclick' handler would suffice. I want to build this so that it works on any link element.
I have no control over what function maybe binded to the onclick event of the link using whichever JS library (not necessarily jQuery) or by simply using JavaScript.
EDIT: With the help of the answers below, it looks like it is possible to check for event handlers attached using jQuery or using the onclick attribute. How do I check for event handlers attached using addEventListener / any other JS library so that it is foolproof?
You can use the the click function to trigger the click event on the selected element.
Example:
$( 'selector for your link' ).click ();
You can learn about various selectors in jQuery's documentation.
EDIT: like the commenters below have said; this only works on events attached with jQuery, inline or in the style of "element.onclick". It does not work with addEventListener, and it will not follow the link if no event handlers are defined.
You could solve this with something like this:
var linkEl = $( 'link selector' );
if ( linkEl.attr ( 'onclick' ) === undefined ) {
document.location = linkEl.attr ( 'href' );
} else {
linkEl.click ();
}
Don't know about addEventListener though.
Why not just the good ol' javascript?
$('#element')[0].click()
Just
$("#your_item").trigger("click");
using .trigger() you can simulate many type of events, just passing it as the parameter.
Easy! Just use jQuery's click function:
$("#theElement").click();
Try this
function submitRequest(buttonId) {
if (document.getElementById(buttonId) == null
|| document.getElementById(buttonId) == undefined) {
return;
}
if (document.getElementById(buttonId).dispatchEvent) {
var e = document.createEvent("MouseEvents");
e.initEvent("click", true, true);
document.getElementById(buttonId).dispatchEvent(e);
} else {
document.getElementById(buttonId).click();
}
}
and you can use it like
submitRequest("target-element-id");
At first see this question to see how you can find if a link has a jQuery handler assigned to it.
Next use:
$("a").attr("onclick")
to see if there is a javascript event assigned to it.
If any of the above is true, then call the click method. If not, get the link:
$("a").attr("href")
and follow it.
I am afraid I don't know what to do if addEventListener is used to add an event handler. If you are in charge of the full page source, use only jQuery event handlers.
All this might not help say when you use rails remote form button to simulate click to. I tried to port nice event simulation from prototype here: my snippets. Just did it and it works for me.

Categories