views:

2096

answers:

3

I know this is similar to this question and this question, but given solutions didn't address the "target" property.

I want to simulate a click to an anchor tag with all extras like correct target handling.

There seems to be a "click()" method for anchor's DOM object but not all browsers support that. Firefox throws this error:

Error: anchorObj.click is not a function

It also works strangely on Opera 10 and Konqueror, causing infinite clicks to happen when it's called inside onclick handler of a surrounding div. I guess only IE8 works fine with it. Anyway I don't want it since major browsers mostly have problems with it.

I found this alternate solution for Firefox in Mozilla forums:

var evt = document.createEvent("MouseEvents"); 
evt.initMouseEvent("click", true, true, window, 
    0, 0, 0, 0, 0, false, false, false, false, 0, null); 
anchorObj.dispatchEvent(evt);

This seems too ugly and cumbersome for me. I don't know how compatible it is and I want to avoid writing browser specific code as much as possible.

I can't use location.href = anchorObj.href; because it doesn't handle "target" attribute. I can do some hard coding based on target's value but I'd like to avoid that as well.

There is suggestion of switching to JQuery but I'm not sure how well it handles target property either since I haven't worked with it before.

+3  A: 

well, you can very quickly test the click dispatch via jQuery like so

$('#link-id').click();

If you're still having problem with click respecting the target, you can always do this

$('#link-id').click( function( event, anchor )
{
  window.open( anchor.href, anchor.target, '' );
  event.preventDefault();
  return false;
});
Peter Bailey
I'm not sure if window.open() uses an existing FRAME if it already exists. I may have target references to other frames as well. Guilty as charged for sticking to frames today :)
ssg
It's trivial to test. You can make a test page in a few minutes and then you'll know.
Peter Bailey
I tested it, it didn't work. It opens a new window on every click.
ssg
+3  A: 

Quoted from https://developer.mozilla.org/en/DOM/element.click

The click method is intended to be used with INPUT elements of type button, checkbox, radio, reset or submit. Gecko does not implement the click method on other elements that might be expected to respond to mouse–clicks such as links (A elements), nor will it necessarily fire the click event of other elements.

Non–Gecko DOMs may behave differently.

Unfortunately it sounds like you have already discovered the best solution to your problem.

As a side note, I agree that your solution seems less than ideal, but if you encapsulate the functionality inside a method (much like JQuery would do) it is not so bad.

Chris Shouts
+8  A: 

Here is a complete test case that simulates the click event, calls all handlers attached (however they have been attached), maintains the "target" attribute ("srcElement" in IE), bubbles like a normal event would, and emulates IE's recursion-prevention. Tested in FF 2, Chrome 2.0, Opera 9.10 and of course IE (6):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
<script>
function fakeClick(event, anchorObj) {
  if (anchorObj.click) {
    anchorObj.click()
  } else if(document.createEvent) {
    if(event.target !== anchorObj) {
      var evt = document.createEvent("MouseEvents"); 
      evt.initMouseEvent("click", true, true, window, 
          0, 0, 0, 0, 0, false, false, false, false, 0, null); 
      var allowDefault = anchorObj.dispatchEvent(evt);
      // you can check allowDefault for false to see if
      // any handler called evt.preventDefault().
      // Firefox will *not* redirect to anchorObj.href
      // for you. However every other browser will.
    }
  }
}
</script>
</head>
<body>

<div onclick="alert('Container clicked')">
  <a id="link" href="#" onclick="alert((event.target || event.srcElement).innerHTML)">Normal link</a>
</div>

<button type="button" onclick="fakeClick(event, document.getElementById('link'))">
  Fake Click on Normal Link
</button>

<br /><br />

<div onclick="alert('Container clicked')">
    <div onclick="fakeClick(event, this.getElementsByTagName('a')[0])"><a id="link2" href="#" onclick="alert('foo')">Embedded Link</a></div>
</div>

<button type="button" onclick="fakeClick(event, document.getElementById('link2'))">Fake Click on Embedded Link</button>

</body>
</html>

Demo here.

It avoids recursion in non-IE browsers by inspecting the event object that is initiating the simulated click, by inspecting the target attribute of the event (which remains unchanged during propagation).

Obviously IE does this internally holding a reference to its global event object. DOM level 2 defines no such global variable, so for that reason the simulator must pass in its local copy of event.

Crescent Fresh
This doesn't address the problem with Opera 10 and Konqueror:<div onclick="fakeClick(this.childNodes[0])"><a target="_blank">test</a>some text that can also be clicked</div>This code causes hundreds of windows to be opened with a single click.
ssg
Although there is no complete answer, I select this as the correct answer since it's the closest.
ssg
Crap, I had more research that I did for this at jsbin.com but I've lost the url (to address your comment of Sep 14th). I'll try to recreate. I take it you're still having this issue?
Crescent Fresh
@ssg: see my update.
Crescent Fresh