How would you trigger a click event from an element that supposedly does not have native clickable behaviours?
For example, I know that you could simply just use the following:
document.getElementById('x').click();
But what happens if 'x' is a 'DIV'? I have an implementation, and it doesn't seem to trigger... I get the error (chrome 12):
Uncaught TypeError: Object #<HTMLDivElement> has no method 'click'
Ideas?
Quick Edit - I'm looking for vanilla JS here... I like reinventing the wheel in my image... :-)
For classic clickable elements like buttons or links, click() should work in all browsers. However for other elements like divs, you need onclick() in some browsers and click() in others.
I would strongly recommend that instead of trying to figure this out for yourself, you use a javascript library such as MooTools, jQuery, Prototype, YUI, or many others. The reason is that getting this stuff right cross-browser is hard. Why waste your time when others have worked and worked to get it right and make it super simple to use? I guarantee that if you spend your time learning how to use a framework you will get farther in your javascript development skill faster. Later you can come back and see how it's all done in the nitty gritty if you want to.
That said, here's script that will work cross-browser, and will do nothing if neither of these properties have a function assigned:
el = document.getElementById('id');
if (el.onclick) {
el.onclick();
} else if (el.click) {
el.click();
}
You could also do this, but perhaps this is a little less clear:
(el.onclick || el.click || function() {})();
Some empirical tests firing the click event on a div:
Firefox 3 and 4 use onclick.
IE7, 8 use both.
Chrome uses onclick (as checked in v. 12.0.742.100).
Safari on iPhone 4 with iOs 4.2.1 uses onclick.
Test script:
var d = document.createElement('div'); d.style.position = 'absolute'; d.style.top = '0'; d.style.left = '0'; d.style.width = '200px'; d.style.height = '200px'; d.style.backgroundColor = '#fff'; d.style.border = '1px solid black'; d.onclick = function() {alert('hello');}; document.body.appendChild(d);
Run this in developer tools in your browser, or javascript: in front and void(0); at the end then paste into the address bar and hit Enter. Then try d.click() and d.onclick(). You can click the div itself to prove it works with real clicks too.
Use this if you actually want to trigger an event programmatically:
function eventFire(el, etype){
if (el.fireEvent) {
(el.fireEvent('on' + etype));
} else {
var evObj = document.createEvent('Events');
evObj.initEvent(etype, true, false);
el.dispatchEvent(evObj);
}
}
//usage
eventFire(document.getElementById('x'),'click');
You will need to feature detect as different browsers (using non-html5 doctype) can support different dom methods:
var ele = document.getElementById('x');
if(typeof ele.click == 'function') {
ele.click()
} else if(typeof ele.onclick == 'function') {
ele.onclick()
}
You can attach an onclick method to anything, but if you don't have any events attached to the actual element itself, it will error out, or simply do nothing.
var el = document.getElementById('x');
el.onclick = function() { //do something };
el.click();
Vanilla JS (without jQuery)
/**
* Simulate a click event.
* #public
* #param {Element} elem the element to simulate a click on
*/
var simulateClick = function (elem) {
// Create our event (with options)
var evt = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
// If cancelled, don't dispatch our event
var canceled = !elem.dispatchEvent(evt);
};
To use it, call the function, passing in the element you want to simulate the click on.
var someLink = document.querySelector('a');
simulateClick(someLink);
https://gomakethings.com/how-to-simulate-a-click-event-with-javascript/
Try doing something like the following:
var my_div = document.getElementById('x');
my_div.onclick = function() {
alert('hello world');
}
I've had a similar issue while trying to use the .click method on stock android browsers. Seems like substituting .click with $('selector').on('click', cb); solves the issue.
Related
I have a hyperlink in my page. I am trying to automate a number of clicks on the hyperlink for testing purposes. Is there any way you can simulate 50 clicks on the hyperlink using JavaScript?
MSDN
I'm looking for onClick event trigger from the JavaScript.
Performing a single click on an HTML element: Simply do element.click(). Most major browsers support this.
To repeat the click more than once: Add an ID to the element to uniquely select it:
Google Chrome
and call the .click() method in your JavaScript code via a for loop:
var link = document.getElementById('my-link');
for(var i = 0; i < 50; i++)
link.click();
You should just use click. For more advanced event firing, use dispatchEvent.
const body = document.body;
body.addEventListener('click', e => {
console.log('clicked body');
});
console.log('Using click()');
body.click();
console.log('Using dispatchEvent');
body.dispatchEvent(new Event('click'));
Original Answer - Obsolete
Here is what I use for IE9+ http://jsfiddle.net/mendesjuan/rHMCy/4/
/**
* Fire an event handler to the specified node. Event handlers can detect that the event was fired programatically
* by testing for a 'synthetic=true' property on the event object
* #param {HTMLNode} node The node to fire the event handler on.
* #param {String} eventName The name of the event without the "on" (e.g., "focus")
*/
function fireEvent(node, eventName) {
// Make sure we use the ownerDocument from the provided node to avoid cross-window problems
var doc;
if (node.ownerDocument) {
doc = node.ownerDocument;
} else if (node.nodeType == 9){
// the node may be the document itself, nodeType 9 = DOCUMENT_NODE
doc = node;
} else {
throw new Error("Invalid node passed to fireEvent: " + node.id);
}
if (node.dispatchEvent) {
// Gecko-style approach (now the standard) takes more work
var eventClass = "";
// Different events have different event classes.
// If this switch statement can't map an eventName to an eventClass,
// the event firing is going to fail.
switch (eventName) {
case "click": // Dispatching of 'click' appears to not work correctly in Safari. Use 'mousedown' or 'mouseup' instead.
case "mousedown":
case "mouseup":
eventClass = "MouseEvents";
break;
case "focus":
case "change":
case "blur":
case "select":
eventClass = "HTMLEvents";
break;
default:
throw "fireEvent: Couldn't find an event class for event '" + eventName + "'.";
break;
}
var event = doc.createEvent(eventClass);
event.initEvent(eventName, true, true); // All events created as bubbling and cancelable.
event.synthetic = true; // allow detection of synthetic events
// The second parameter says go ahead with the default action
node.dispatchEvent(event, true);
} else if (node.fireEvent) {
// IE-old school style, you can drop this if you don't need to support IE8 and lower
var event = doc.createEventObject();
event.synthetic = true; // allow detection of synthetic events
node.fireEvent("on" + eventName, event);
}
};
Note that calling fireEvent(inputField, 'change'); does not mean it will actually change the input field. The typical use case for firing a change event is when you set a field programmatically and you want event handlers to be called since calling input.value="Something" won't trigger a change event.
What
l.onclick();
does is exactly calling the onclick function of l, that is, if you have set one with l.onclick = myFunction;. If you haven't set l.onclick, it does nothing. In contrast,
l.click();
simulates a click and fires all event handlers, whether added with l.addEventHandler('click', myFunction);, in HTML, or in any other way.
I'm quite ashamed that there are so many incorrect or undisclosed partial applicability.
The easiest way to do this is through Chrome or Opera (my examples will use Chrome) using the Console. Enter the following code into the console (generally in 1 line):
var l = document.getElementById('testLink');
for(var i=0; i<5; i++){
l.click();
}
This will generate the required result
.click() does not work with Android (look at mozilla docs, at mobile section). You can trigger the click event with this method:
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();
}
}
From this post
Use a testing framework
This might be helpful - http://seleniumhq.org/ - Selenium is a web application automated testing system.
You can create tests using the Firefox plugin Selenium IDE
Manual firing of events
To manually fire events the correct way you will need to use different methods for different browsers - either el.dispatchEvent or el.fireEvent where el will be your Anchor element. I believe both of these will require constructing an Event object to pass in.
The alternative, not entirely correct, quick-and-dirty way would be this:
var el = document.getElementById('anchorelementid');
el.onclick(); // Not entirely correct because your event handler will be called
// without an Event object parameter.
IE9+
function triggerEvent(el, type){
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
}
Usage example:
var el = document.querySelector('input[type="text"]');
triggerEvent(el, 'mousedown');
Source: https://plainjs.com/javascript/events/trigger-an-event-11/
Please call trigger function any where and button will click.
<a href="#" id="myBtn" title="" >Button click </a>
function trigger(){
document.getElementById("myBtn").click();
}
Fair warning:
element.onclick() does not behave as expected. It only runs the code within onclick="" attribute, but does not trigger default behavior.
I had similar issue with radio button not setting to checked, even though onclick custom function was running fine. Had to add radio.checked = "true"; to set it. Probably the same goes and for other elements (after a.onclick() there should be also window.location.href = "url";)
this is part of my code (where event listeners are added to my images).
var overlay = this.overlay;
var icon_holder = this.icon_hld;
var docfrag = document.createDocumentFragment();
var images = holder.querySelectorAll('img');
var that = this;
function video_play() {
console.log(this);
this.style.display = 'none';
this.parentNode.querySelector('.JGalleryMedia').style.display = '';
this.parentNode.querySelector('.JGalleryMedia').play();
this.parentNode.querySelector('.JGalleryMedia').autoplay = true;
}
[].forEach.call(images, function (img) {
img.addEventListener('click', JGallery.prototype.showMe.bind(that), false);
}
}
this is working nicly in opera and chrome, but not working in IE and FF.
I've seen caniuse.com, but I have not found anything I should not use in my code. If you want to see the working demo open zaervax.ir with chrome or opera and go to gallery and click on image thumbnails.
I am not sure but I think you cannot pass parameters like this in the eventListener.
You could try an anonymous function like this:
img.addEventListener('click', function(){
JGallery.prototype.showMe.bind(that)
}, false);
Also if you want to pass this as a parameters you can use the ES6 Arrow functions, so that you will be able to access this in your showMe() function. It is done like that:
img.addEventListener('click', event => this.JGallery.prototype.showMe(event), false);
More infos about arrow functions
If this is not working, can you try to open your console and tell us if there is any error message?
ok IE problem was about forEach (without .call)(I had this in several lines above the mentioned lines). and FF (v47) seems to has problems with forEach. I have updated my FF (to v50)(problem solved without code changing). And I decided not to use forEach ever again, and I used while instead. like so...
var i = 0;
while(i < images.length){
var img = images.item(i);
img.addEventListener('click', JGallery.prototype.showMe.bind(that), false);
}
and now it's working nicely, you can check it out in zaervax.ir
Essentially I'm creating a custom video control bar for an html5 video element. Everything works fine except for the seek bar for which I'm using a range input element.
Now for each element in the control bar, I'm assigning it to a variable in a js function which is called upon window load and adding event listeners. Like so:
function handleWindowLoad() {
var video = document.getElementById ("video");
var playPause = document.getElementById ("playPause");
var muteUnmute = document.getElementById ("muteUnmute");
var fullScreen = document.getElementById ("toggleFullscreen");
var scrubSlider = document.getElementById ("seekBar");
playPause.addEventListener ("click", togglePlay);
muteUnmute.addEventListener("click", toggleMute);
fullScreen.addEventListener("click", toggleFullscreen);
scrubSlider.addEventListener("change", scrubVideo);
}
All the event handlers work without a hitch.
e.g:
function togglePlay() {
if (video.paused) {
video.play();
playPause.innerHTML = "Pause";
}
else {
video.pause();
playPause.innerHTML = "Play";
}
}
works just fine.
However the scrubSlider event handler, scrubVideo():
function scrubVideo() {
var scrubTime = video.duration * (scrubSlider.value/100);
video.currentTime = scrubTime;
}
throws a "scrubSlider undefined" error.
The event listener works fine as scrubVideo() is called when expected but outside of the handleWindowLoad() function I am unable to access scrubSlider. The only ways around this error I've tried are using document.getElementById instead of the var or by declaring scrubSlider globally.
I find this interesting as the only differences between scrubSlider and the rest of the elements is that the element in question is an <input> and not a <button> and the event being listened for is a "change" instead of a "click".
Is this error a result of some sort of inherent functionality of the HTML element or something way more trivial which I've simply overlooked?
Here's a JSFiddle
If I see well, you define scrubSlider in the handleWindowLoad function (which makes it only available in that scope) and you try to access it in scrubVideo. To make it work do something like this:
var scrubSlider;
function handleWindowLoad() {
scrubSlider = document.getElementById ("seekBar");
...
}
EDIT:
Funny thing that I didn't know: apparently you reach the html elements by their id in javascript, if you subscribe to the DOMContentLoaded event. https://jsfiddle.net/22oqpcLu/1/
So, this is the reason that you don't get undefined while accessing the video variable. I guess you could access scrubSlider as seekBar.
EDIT:
I've made the changes Matthew and Yossi suggested and it still doesn't seem to work. Those changes I've edited in the post below too.
It now works!
I have a question for a particular problem I can't solve. If you know this question has been answered please send me the link as an answer. I'm trying not to use a framework in this case, but can use jQuery if necessary.
I have found answers on how to attach listeners via functions but I need something so as I wouldn't have to refactor all the code I already have. I'm a freelancer and am working on somebody else's code.
What happens is that I want to detect a touch event for a touch device. This code should work for a PC too so I need to detect clicks. There's this DIV which is created programatically to which I need to add the click or touch, depending on the device. Originally the function was called from an onmousedown event like this:
arrDivAnswers[c].onmousedown = onQuestionDown;
And this is the function it calls:
function onQuestionDown(e)
{
if(!itemSelected)
{
if(this.getAttribute('data-isCorrect') == 'true')
setStyleQCorrect(this, true);
else
setStyleQIncorrect(this);
this.querySelector('.answerText').style.color = '#ffffff';
this.querySelector('.isCorrect').style.visibility = 'visible';
}
itemSelected = true;
}
This was working fine. Now I've made this one which would try and select the correct event for a click or touch (I need a function because I have to use this more than once - and the isTouchDevice is working fine. I use that on some other apps so that code is pretty short and has been tested):
function detectEventClickOrTouch(element, functionToCall){
//detectEventClickOrTouch(arrDivAnswers[c], 'onQuestionDown');
if(isTouchDevice()){
element.addEventListener("touchend", functionToCall, false);
} else{
element.addEventListener("click", functionToCall, false);
}
}
The DIV element gets created like this on some loop:
arrDivAnswers[c] = document.createElement('div');
console.log( "Answer object #" + c + " = " + arrDivAnswers[c] );
arrDivAnswers[c].className = 'autosize';
arrDivAnswers[c].style.textAlign = 'left';
arrDivAnswers[c].setAttribute('data-isCorrect',false);
arrDivAnswers[c].setAttribute('data-isSelected',false);
divAnswerContainer.appendChild(arrDivAnswers[c]);
And then the events get attached to it like this (the older method has been commented out):
for(c;c < arrQuestions[index].arrAnswers.length;c++)
{
var curAnswer = arrQuestions[index].arrAnswers[c];
arrDivAnswers[c].onmouseover = function (e){setStyleQHover(e.currentTarget)};
arrDivAnswers[c].onmouseout = function (e){setStyleQUp(e.currentTarget)};
// Detect touch here *************************
detectEventClickOrTouch(arrDivAnswers[c], onQuestionDown);
//arrDivAnswers[c].onmousedown = onQuestionDown;
// Detect touch here *************************
arrDivAnswers[c].style.visibility = 'visible';
arrDivAnswers[c].querySelector('.answerText').innerHTML = curAnswer.strAnswer;
arrDivAnswers[c].setAttribute('data-isCorrect',curAnswer.isCorrect);
if(curAnswer.isCorrect)
{
//arrDivAnswers[c].classList.add("correctAnswer");
arrDivAnswers[c].className = "correctAnswer";
}
else
{
//arrDivAnswers[c].classList.remove("correctAnswer");
arrDivAnswers[c].className = "autosize";
}
arrDivAnswers[c].setAttribute('data-isSelected',false);
setStyleQUp(arrDivAnswers[c]);
itemSelected = false;
}
[...]
The debugger is throwing this error:
Uncaught TypeError: Object [object DOMWindow] has no method 'getAttribute'
I'm sure I'm messing up the "this" because I'm not calling the function properly.
I agree the "this" variable is getting messed up. The problem is that you are attaching an anonymous function as the callback that then calls eval on another method. This seems unnecessary.
Could you just do this:
function detectEventClickOrTouch(element, functionToCall){
//detectEventClickOrTouch(arrDivAnswers[c], 'onQuestionDown');
if(isTouchDevice()){
element.addEventListener("touchend", functionToCall, false);
} else{
element.addEventListener("click", functionToCall, false);
}
}
And then when you attach the event just do:
detectEventClickOrTouch(arrDivAnswers[c], onQuestionDown);
Since you now call the onQuestionDown function indirectly by the eval the this context seen by the onQuestionDown is the global namespace and not the the element which fired the event.
You don't need the eval anyway... you can pass the function it self
detectEventClickOrTouch(arrDivAnswers[c], onQuestionDown);
and:
element.addEventListener("touchend", functionToCall, false);
I have a hyperlink in my page. I am trying to automate a number of clicks on the hyperlink for testing purposes. Is there any way you can simulate 50 clicks on the hyperlink using JavaScript?
MSDN
I'm looking for onClick event trigger from the JavaScript.
Performing a single click on an HTML element: Simply do element.click(). Most major browsers support this.
To repeat the click more than once: Add an ID to the element to uniquely select it:
Google Chrome
and call the .click() method in your JavaScript code via a for loop:
var link = document.getElementById('my-link');
for(var i = 0; i < 50; i++)
link.click();
You should just use click. For more advanced event firing, use dispatchEvent.
const body = document.body;
body.addEventListener('click', e => {
console.log('clicked body');
});
console.log('Using click()');
body.click();
console.log('Using dispatchEvent');
body.dispatchEvent(new Event('click'));
Original Answer - Obsolete
Here is what I use for IE9+ http://jsfiddle.net/mendesjuan/rHMCy/4/
/**
* Fire an event handler to the specified node. Event handlers can detect that the event was fired programatically
* by testing for a 'synthetic=true' property on the event object
* #param {HTMLNode} node The node to fire the event handler on.
* #param {String} eventName The name of the event without the "on" (e.g., "focus")
*/
function fireEvent(node, eventName) {
// Make sure we use the ownerDocument from the provided node to avoid cross-window problems
var doc;
if (node.ownerDocument) {
doc = node.ownerDocument;
} else if (node.nodeType == 9){
// the node may be the document itself, nodeType 9 = DOCUMENT_NODE
doc = node;
} else {
throw new Error("Invalid node passed to fireEvent: " + node.id);
}
if (node.dispatchEvent) {
// Gecko-style approach (now the standard) takes more work
var eventClass = "";
// Different events have different event classes.
// If this switch statement can't map an eventName to an eventClass,
// the event firing is going to fail.
switch (eventName) {
case "click": // Dispatching of 'click' appears to not work correctly in Safari. Use 'mousedown' or 'mouseup' instead.
case "mousedown":
case "mouseup":
eventClass = "MouseEvents";
break;
case "focus":
case "change":
case "blur":
case "select":
eventClass = "HTMLEvents";
break;
default:
throw "fireEvent: Couldn't find an event class for event '" + eventName + "'.";
break;
}
var event = doc.createEvent(eventClass);
event.initEvent(eventName, true, true); // All events created as bubbling and cancelable.
event.synthetic = true; // allow detection of synthetic events
// The second parameter says go ahead with the default action
node.dispatchEvent(event, true);
} else if (node.fireEvent) {
// IE-old school style, you can drop this if you don't need to support IE8 and lower
var event = doc.createEventObject();
event.synthetic = true; // allow detection of synthetic events
node.fireEvent("on" + eventName, event);
}
};
Note that calling fireEvent(inputField, 'change'); does not mean it will actually change the input field. The typical use case for firing a change event is when you set a field programmatically and you want event handlers to be called since calling input.value="Something" won't trigger a change event.
What
l.onclick();
does is exactly calling the onclick function of l, that is, if you have set one with l.onclick = myFunction;. If you haven't set l.onclick, it does nothing. In contrast,
l.click();
simulates a click and fires all event handlers, whether added with l.addEventHandler('click', myFunction);, in HTML, or in any other way.
I'm quite ashamed that there are so many incorrect or undisclosed partial applicability.
The easiest way to do this is through Chrome or Opera (my examples will use Chrome) using the Console. Enter the following code into the console (generally in 1 line):
var l = document.getElementById('testLink');
for(var i=0; i<5; i++){
l.click();
}
This will generate the required result
.click() does not work with Android (look at mozilla docs, at mobile section). You can trigger the click event with this method:
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();
}
}
From this post
Use a testing framework
This might be helpful - http://seleniumhq.org/ - Selenium is a web application automated testing system.
You can create tests using the Firefox plugin Selenium IDE
Manual firing of events
To manually fire events the correct way you will need to use different methods for different browsers - either el.dispatchEvent or el.fireEvent where el will be your Anchor element. I believe both of these will require constructing an Event object to pass in.
The alternative, not entirely correct, quick-and-dirty way would be this:
var el = document.getElementById('anchorelementid');
el.onclick(); // Not entirely correct because your event handler will be called
// without an Event object parameter.
IE9+
function triggerEvent(el, type){
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
}
Usage example:
var el = document.querySelector('input[type="text"]');
triggerEvent(el, 'mousedown');
Source: https://plainjs.com/javascript/events/trigger-an-event-11/
Please call trigger function any where and button will click.
<a href="#" id="myBtn" title="" >Button click </a>
function trigger(){
document.getElementById("myBtn").click();
}
Fair warning:
element.onclick() does not behave as expected. It only runs the code within onclick="" attribute, but does not trigger default behavior.
I had similar issue with radio button not setting to checked, even though onclick custom function was running fine. Had to add radio.checked = "true"; to set it. Probably the same goes and for other elements (after a.onclick() there should be also window.location.href = "url";)