Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery click() on a div button won't fire

I am trying to emulate a user's click on a site who's code I do not control. The element I am trying to engage with a div acting as button.

<div role="button" class="c-T-S a-b a-b-B a-b-Ma oU v2" aria-disabled="false" style="-webkit-user-select: none;" tabindex="0">
    Generate
</div>

The event listeners that are associated with element (according to Chrome's inspector) are:

enter image description here

And I am simply trying to click the button using:

var button = $('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2')
button.click()

... but nothing happens. The selector is valid, as verified by:

alert($('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2').length); // alerts "1"

I have tried permutations of all the event handlers

button.trigger('click');
button.mouseover().mousedown().mouseup()
button.trigger('mouseover', function() { button.trigger('mousedown', function() { button.trigger('mouseup'); });  });

... but still nothing. How can I simulate a click on this div?

In case it is not clear, I am trying to simulate a click on this div and trigger the original function, not define a new click function on the element.

UPDATE

Many of these answer do indeed click the button, but don't produce the same result as manually clicking the button. So it appears the problem is not necessarily clicking the button per se, but emulating a real click.

like image 465
coneybeare Avatar asked Sep 30 '14 17:09

coneybeare


People also ask

Why click function is not working in jQuery?

jQuery click not working at the time page loading, jQuery Onclick Method is tried to an element or selector. As a result, the binding will fail if the element we wish to click isn't present when the page is ready.

Can you give a Div an onClick?

To set an onClick listener on a div element in React:Set the onClick prop on the div. The function you pass to the prop will get called every time the div is clicked. You can access the div as event.

How do you trigger a click element?

The HTMLElement. click() method simulates a mouse click on an element. When click() is used with supported elements (such as an <input> ), it fires the element's click event. This event then bubbles up to elements higher in the document tree (or event chain) and fires their click events.

What is a click event?

An element receives a click event when a pointing device button (such as a mouse's primary mouse button) is both pressed and released while the pointer is located inside the element.


1 Answers

I have made a FIDDLE to simulate your "non-clickable" button. The blue div there has the same eventListeners attached as you have shown in your question. Playing around ended up with following results:

1) Let's get the DOM-element first:

var button = document.getElementsByClassName('.c-T-S.a-b.a-b-B.a-b-Ma.oU.v2')[0];

2) The page doesn't include jQuery. So all eventListeners there are attached by native .addEventListener(). If you use jQuery to trigger events, it triggers only the events that are attached by jQuery, but not the native attached events. That means:

$(button).trigger('mousedown'); // this doesn't work
button.dispatchEvent(new Event('mousedown')); // this should work

3) As Scimonster pointed out, there is no click-eventListener attached. That means:

$(button).trigger('click'); // doesn't work anyway, see 2)
// next works, but has no visible result on the page,
// because there is no click-handler to do anything:
button.dispatchEvent(new Event('click'));

4) The click-event fires when the mousebutton goes up. When the mouseup-event is used instead it looks like a click. In the fiddle the mouseup makes the red div visible. You may try to trigger the mouseup-event by adding this line to the code:

button.dispatchEvent(new Event('mouseup')); // "works", but has no visible result

The mouseup-handler is "hidden" by the mouseover- and mouseout-events, the first attaches it and the latter removes it. That way mouseup has only a result when mouse is over the button. I assume your google-page does something similar to cover the click-event.

5) What you should try:

First trigger some single events in native way:

button.dispatchEvent(new Event('eventName'));

If that gives no usable results use some reasonable combinations of events:

button.dispatchEvent(new Event('mouseover'));
button.dispatchEvent(new Event('mousedown'));
// or:
button.dispatchEvent(new Event('mousedown'));
button.dispatchEvent(new Event('mouseup')); // or: .....

There are many ways to combine events so that a single event doesn't do anything, but only the right combination works.

EDIT According to your invitation to investigate the source I found two ways:

1) The button itself has no eventListeners attached. The button is wrapped in an <a>-tag. This tag is parent of the button and its attribute jsaction 's value tells that <a> has listeners for click, focus, and mousedown. Targeting it directly works:

button.parentElement.dispatchEvent(new Event('click'));

2) If you want to click the button itself you must trigger an event that bubbles up the DOM to reach an element that has a click-handler. But when creating an event with new Event('name'), its bubbles-property defaults to false. It was my bad not thinking of that.. So the following works directly on the button:

button.dispatchEvent(new Event('click', {bubbles: true}));

EDIT 2 Digging deeper in whats going on on that page yielded an usable result:

It has been found that the page takes care of the mouse-pointer position and right order of the events, probable to distinguish wether a human or a robot/script triggers the events. Therefore this solution uses the MouseEvent - object containing the clientX and clientY properties, which holds the coordinates of the pointer when the event is fired.

A natural "click" on an element always triggers four events in given order: mouseover, mousedown, mouseup, and click. To simulate a natural behaviour mousedown and mouseup are delayed. To make it handy all steps are wrapped in a function which simulates 1) enter element at it's topLeft corner, 2) click a bit later at elements center. For details see comments.

function simulateClick(elem) {
    var rect = elem.getBoundingClientRect(), // holds all position- and size-properties of element
        topEnter = rect.top,
        leftEnter = rect.left, // coordinates of elements topLeft corner
        topMid = topEnter + rect.height / 2,
        leftMid = topEnter + rect.width / 2, // coordinates of elements center
        ddelay = (rect.height + rect.width) * 2, // delay depends on elements size
        ducInit = {bubbles: true, clientX: leftMid, clientY: topMid}, // create init object
        // set up the four events, the first with enter-coordinates,
        mover = new MouseEvent('mouseover', {bubbles: true, clientX: leftEnter, clientY: topEnter}),
        // the other with center-coordinates
        mdown = new MouseEvent('mousedown', ducInit),
        mup = new MouseEvent('mouseup', ducInit),
        mclick = new MouseEvent('click', ducInit);
    // trigger mouseover = enter element at toLeft corner
    elem.dispatchEvent(mover);
    // trigger mousedown  with delay to simulate move-time to center
    window.setTimeout(function() {elem.dispatchEvent(mdown)}, ddelay);
    // trigger mouseup and click with a bit longer delay
    // to simulate time between pressing/releasing the button
    window.setTimeout(function() {
        elem.dispatchEvent(mup); elem.dispatchEvent(mclick);
    }, ddelay * 1.2);
}

// now it does the trick:
simulateClick(document.querySelector(".c-T-S.a-b.a-b-B.a-b-Ma.oU.v2"));

The function does not simulate the real mouse movement being unnecessary for the given task.

like image 140
Martin Ernst Avatar answered Oct 07 '22 03:10

Martin Ernst