Can I call jQuery's click() to follow an <a> link if I haven't bound an event handler to it with bind or click already?
Asked Answered
H

10

176

I have a timer in my JavaScript which needs to emulate clicking a link to go to another page once the time elapses. To do this I'm using jQuery's click() function. I have used $().trigger() and window.location also, and I can make it work as intended with all three.

I've observed some weird behavior with click() and I'm trying to understand what happens and why.

I'm using Firefox for everything I describe in this question, but I am also interested in what other browsers will do with this.

If I have not used $('a').bind('click',fn) or $('a').click(fn) to set an event handler, then calling $('a').click() seems to do nothing at all. It does not call the browser's default handler for this event, as the browser does not load the new page.

However, if I set an event handler first, then it works as expected, even if the event handler does nothing.

$('a').click(function(){return true;}).click();

This loads the new page as if I had clicked the a myself.

So my question is twofold: Is this weird behavior because I'm doing something wrong somewhere? and why does calling click() do nothing with the default behavior if I haven't created a handler of my own?


As Hoffman determined when he tried to duplicate my results, the outcome I described above doesn't actually happen. I'm not sure what caused the events I observed yesterday, but I'm certain today that it was not what I described in the question.

So the answer is that you can't "fake" clicks in the browser and that all jQuery does is call your event handler. You can still use window.location to change page, and that works fine for me.

Hirschfeld answered 7/11, 2009 at 22:2 Comment(1)
Might be a solution: #31688259Cowgirl
P
90

Interesting, this is probably a "feature request" (ie bug) for jQuery. The jQuery click event only triggers the click action (called onClick event on the DOM) on the element if you bind a jQuery event to the element. You should go to jQuery mailing lists ( http://forum.jquery.com/ ) and report this. This might be the wanted behavior, but I don't think so.

EDIT:

I did some testing and what you said is wrong, even if you bind a function to an 'a' tag it still doesn't take you to the website specified by the href attribute. Try the following code:

<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
 <script>
  $(document).ready(function() {
   /* Try to dis-comment this:
   $('#a').click(function () {
    alert('jQuery.click()');
    return true;
   });
   */
  });
  function button_onClick() {
   $('#a').click();
  }
  function a_onClick() {
   alert('a_onClick');
  }
 </script>

</head>
<body>
 <input type="button" onclick="button_onClick()">
 <br>
 <a id='a' href='http://www.google.com' onClick="a_onClick()"> aaa </a>

</body>
</html> 

It never goes to google.com unless you directly click on the link (with or without the commented code). Also notice that even if you bind the click event to the link it still doesn't go purple once you click the button. It only goes purple if you click the link directly.

I did some research and it seems that the .click is not suppose to work with 'a' tags because the browser does not suport "fake clicking" with javascript. I mean, you can't "click" an element with javascript. With 'a' tags you can trigger its onClick event but the link won't change colors (to the visited link color, the default is purple in most browsers). So it wouldn't make sense to make the $().click event work with 'a' tags since the act of going to the href attribute is not a part of the onClick event, but hardcoded in the browser.

Pharyngeal answered 7/11, 2009 at 23:27 Comment(3)
I tried your code, and it does exactly as you said it does, but my code does as I described above. I'll do some more experiments and see if I can put together a simple example of my results that you can try.Hirschfeld
Ok. It must have been something I did wrong. I was absolutely certain at the time I posted my question that it was working, but since I tried your example mine no longer works. I'll just go back to using window.location to change the page and not try faking the click.Hirschfeld
Indeed, the click() is not meant to create fake clicks but sometimes we can use it to click buttons or forms with javascript injections or just for the convenience while creating a temporary hotkey on top of existing javascript functions.Parrish
D
244

Another option is of course to just use vanilla JavaScript:

document.getElementById("a_link").click()
Deepseated answered 9/10, 2012 at 13:46 Comment(12)
This does not work in Safari, and according to HTML spec only inputs need implement this.Fatalism
Dang! This does work! But I must say that it isn't quite "vanilla" javascript since it's using a jquery element, so it's sort-of-vanilla jquery javascript.... It works in Firefox 24 and IE 10.Himelman
@BGM, ok, but the click() isn't on a jquery element. You could replace it by getElementById("..").click()Deepseated
wow wounder full, works as I expected. +1 given :). For other users, you can also use like: var lnk = document.getElementById("a_link"); if (lnk == null) { //do some.... } else { lnk.click(); }Hashum
Tested in various browsers, IE10 & Jquery 1.6.4 can't handle this.Sweeting
@HeanzoBeanzo : Jquery has nothing to do with it, the click is not on a jqeuery element. Afa IE10 is concerned: in standard mode, it works for meDeepseated
$("#a_link") is a jQuery element, and the method click() is also from jQuery (if you included the library). I switched to JQuery 1.8 and it worked.Sweeting
@HeanzoBeanzo, no that is not true. [0] is unwrapping the object, the click has never to do with jquery. $("a") instanceof jQuery--> true ; $("a")[0] instanceof jQuery --> false. The example is the same as document.getElementById("a_link").click().Deepseated
Counter-intuitive that the [0] is necessary at all. But thanks for this. This should, of course, be the accepted answer.Copley
Is there a way to distinguish between a real mouse click event and this plain javascript .click() event? Using pageX/Y etc. is not ideal since IE7 doesn't set these values to 0 when programmatically clicked.Robichaud
@vishalsharma, as of HTML 5 spec, it looks like HTMLElement has a click function for that precise purpose. See on w3c here and here. Dom level 2/3 specs seem to lag a bit on specifying html 5 impacts.Noelianoell
In JQuery : $(...).get(0).click()Eduction
P
90

Interesting, this is probably a "feature request" (ie bug) for jQuery. The jQuery click event only triggers the click action (called onClick event on the DOM) on the element if you bind a jQuery event to the element. You should go to jQuery mailing lists ( http://forum.jquery.com/ ) and report this. This might be the wanted behavior, but I don't think so.

EDIT:

I did some testing and what you said is wrong, even if you bind a function to an 'a' tag it still doesn't take you to the website specified by the href attribute. Try the following code:

<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
 <script>
  $(document).ready(function() {
   /* Try to dis-comment this:
   $('#a').click(function () {
    alert('jQuery.click()');
    return true;
   });
   */
  });
  function button_onClick() {
   $('#a').click();
  }
  function a_onClick() {
   alert('a_onClick');
  }
 </script>

</head>
<body>
 <input type="button" onclick="button_onClick()">
 <br>
 <a id='a' href='http://www.google.com' onClick="a_onClick()"> aaa </a>

</body>
</html> 

It never goes to google.com unless you directly click on the link (with or without the commented code). Also notice that even if you bind the click event to the link it still doesn't go purple once you click the button. It only goes purple if you click the link directly.

I did some research and it seems that the .click is not suppose to work with 'a' tags because the browser does not suport "fake clicking" with javascript. I mean, you can't "click" an element with javascript. With 'a' tags you can trigger its onClick event but the link won't change colors (to the visited link color, the default is purple in most browsers). So it wouldn't make sense to make the $().click event work with 'a' tags since the act of going to the href attribute is not a part of the onClick event, but hardcoded in the browser.

Pharyngeal answered 7/11, 2009 at 23:27 Comment(3)
I tried your code, and it does exactly as you said it does, but my code does as I described above. I'll do some more experiments and see if I can put together a simple example of my results that you can try.Hirschfeld
Ok. It must have been something I did wrong. I was absolutely certain at the time I posted my question that it was working, but since I tried your example mine no longer works. I'll just go back to using window.location to change the page and not try faking the click.Hirschfeld
Indeed, the click() is not meant to create fake clicks but sometimes we can use it to click buttons or forms with javascript injections or just for the convenience while creating a temporary hotkey on top of existing javascript functions.Parrish
E
65

If you look at the code for the $.click function, I'll bet there is a conditional statement that checks to see if the element has listeners registered for theclick event before it proceeds. Why not just get the href attribute from the link and manually change the page location?

 window.location.href = $('a').attr('href');

Here is why it doesn't click through. From the trigger function, jQuery source for version 1.3.2:

 // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
 if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
     event.result = false;

 // Trigger the native events (except for clicks on links)
 if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
     this.triggered = true;
     try {
         elem[ type ]();
         // Prevent Internet Explorer from throwing an error for some hidden elements
     }
     catch (e)
     {
     }
 }

After it calls handlers (if there are any), jQuery triggers an event on the object. However it only calls native handlers for click events if the element is not a link. I guess this was done purposefully for some reason. This should be true though whether an event handler is defined or not, so I'm not sure why in your case attaching an event handler caused the native onClick handler to be called. You'll have to do what I did and step through the execution to see where it is being called.

Ephor answered 7/11, 2009 at 22:13 Comment(3)
I can certainly use window.location and the href as I mentioned in the question. I'm trying to understand what happens in jquery click(), and what causes the results I observed.Hirschfeld
I edited my answer to show where in jQuery source it deals with $.click() calls on links.Ephor
window.location works, but not not post HTTP Referrer, and breaks the back button.Prynne
R
6

JavaScript/jQuery doesn't support the default behavior of links "clicked" programmatically.

Instead, you can create a form and submit it. This way you don't have to use window.location or window.open, which are often blocked as unwanted popups by browsers.

This script has two different methods: one that tries to open three new tabs/windows (it opens only one in Internet Explorer and Chrome, more information is below) and one that fires a custom event on a link click.

Here is how:

HTML

<html>
<head>
    <script src="jquery-1.9.1.min.js" type="text/javascript"></script>
    <script src="script.js" type="text/javascript"></script>
</head>

<body>
    <button id="testbtn">Test</button><br><br>

    <a href="https://google.nl">Google</a><br>
    <a href="http://en.wikipedia.org/wiki/Main_Page">Wikipedia</a><br>
    <a href="https://stackoverflow.com/">Stack Overflow</a>
</body>

</html>

jQuery (file script.js)

$(function()
{
    // Try to open all three links by pressing the button
    // - Firefox opens all three links
    // - Chrome only opens one of them without a popup warning
    // - Internet Explorer only opens one of them WITH a popup warning
    $("#testbtn").on("click", function()
    {
        $("a").each(function()
        {
            var form = $("<form></form>");
            form.attr(
            {
                id     : "formform",
                action : $(this).attr("href"),
                method : "GET",
                // Open in new window/tab
                target : "_blank"
            });

            $("body").append(form);
            $("#formform").submit();
            $("#formform").remove();
        });
    });

    // Or click the link and fire a custom event
    // (open your own window without following 
    // the link itself)
    $("a").on("click", function()
    {
        var form = $("<form></form>");
        form.attr(
        {
            id     : "formform",
            // The location given in the link itself
            action : $(this).attr("href"),
            method : "GET",
            // Open in new window/tab
            target : "_blank"
        });

        $("body").append(form);
        $("#formform").submit();
        $("#formform").remove();

        // Prevent the link from opening normally
        return false;
    });
});

For each link element, it:

  1. Creates a form
  2. Gives it attributes
  3. Appends it to the DOM so it can be submitted
  4. Submits it
  5. Removes the form from the DOM, removing all traces *Insert evil laugh*

Now you have a new tab/window loading "https://google.nl" (or any URL you want, just replace it). Unfortunately when you try to open more than one window this way, you get an Popup blocked messagebar when trying to open the second one (the first one is still opened).


More information on how I got to this method is found here:

Reticulation answered 3/4, 2013 at 15:3 Comment(0)
C
5

Click handlers on anchor tags are a special case in jQuery.

I think you might be getting confused between the anchor's onclick event (known by the browser) and the click event of the jQuery object which wraps the DOM's notion of the anchor tag.

You can download the jQuery 1.3.2 source here.

The relevant sections of the source are lines 2643-2645 (I have split this out to multiple lines to make it easier to comprehend):

// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
if (
     (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && 
       elem["on"+type] && 
       elem["on"+type].apply( elem, data ) === false
   )
     event.result = false;
Calceiform answered 7/11, 2009 at 23:8 Comment(0)
P
5

You can use jQuery to select the jQuery object for that element. Then, get the underlying DOM element and call its click() method.

By id:

$("#my-link").each(function (index) { $(this).get(0).click() });

Or use jQuery to click a bunch of links by CSS class:

$(".my-link-class").each(function (index) { $(this).get(0).click() });
Phosphide answered 9/2, 2017 at 16:53 Comment(0)
O
3

Trigger a hyperlink <a> element that is inside the element you want to hookup the jQuery .click() to:

<div class="TopicControl">
    <div class="articleImage">
       <a href=""><img src="" alt=""></a>
    </div>
</div>

In your script you hookup to the main container you want the click event on. Then you use standard jQuery methodology to find the element (type, class, and id) and fire the click. jQuery enters a recursive function to fire the click and you break the recursive function by taking the event 'e' and stopPropagation() function and return false, because you don't want jQuery to do anything else but fire the link.

$('.TopicControl').click(function (event) {
    $(this).find('a').click();
    event.stopPropagation();
    return false;
});

Alternative solution is to wrap the containers in the <a> element and place 's as containers inside instead of <div>'s. Set the spans to display block to conform with W3C standards.

Oxycephaly answered 9/10, 2012 at 17:46 Comment(0)
M
2

It does nothing because no events have been bound to the event. If I recall correctly, jQuery maintains its own list of event handlers that are bound to NodeLists for performance and other purposes.

Mcgrew answered 7/11, 2009 at 22:8 Comment(0)
D
2

If you need this feature for one case or very few cases (your whole application is not requiring this feature). I would rather leave jQuery as is (for many reasons, including being able to update to newer versions, CDN, etc.) and have the following workaround:

// For modern browsers
$(ele).trigger("click");

// Relying on Paul Irish's conditional class names,
// <https://www.paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/>
// (via HTML5 Boilerplate, <https://html5boilerplate.com/>) where
// each Internet Explorer version gets a class of its version
$("html.ie7").length && (function(){
    var eleOnClickattr = $(ele).attr("onclick")
    eval(eleOnClickattr);
})()
Dribble answered 15/4, 2012 at 18:3 Comment(0)
G
1

To open hyperlink in the same tab, use:

$(document).on('click', "a.classname", function() {
    var form = $("<form></form>");
    form.attr(
    {
        id     : "formid",
        action : $(this).attr("href"),
        method : "GET",
    });

    $("body").append(form);
    $("#formid").submit();
    $("#formid").remove();
    return false;
});
Godfrey answered 11/2, 2016 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.