skip to Main Content

Similar quesitions have been asked but, they, and their answers, didn’t actually pass all the info.

Example

document.querySelector('#b').addEventListener('click', (e) => {
  document.querySelector('#a').click();
});
<a id="a" href="https://wikipedia.org">google raw</a>
<button id="b" type="button">click me while holding Ctrl on windows or Cmd on Mac</button>

What should happen:

You Ctrl click the button on Windows or Cmd click the button on Mac and wikipedia opens in a new tab. You click without a key it opens in the same tab. Exactly how a click on the <a> tag works.

What happens instead:

The Ctrl/Cmd is not passed on to click() and so you get the behavior without the Ctrl/Cmd

Note: A solution that only passes on Ctrl/Cmd might be okay but ideally you’d pass everything what other info might be relevant

If you’re curious about the use case I have list of files in a table

<tr><td><a href="...">filename</a></td><td>size</td><td>date</td></tr>

And I want it so if you click anywhere in the row you it’s as though you clicked the link. I can’t change the HTML because Kodi and other similar programs incorrectly parse HTML for filenames and they’re hardcoded to expect whatever HTML was the norm for nginx at the time they wrote their parser 🤷‍♂️

3

Answers


  1. Chosen as BEST ANSWER

    This seems to work, though no idea if it's portable to old browsers or has other issues.

    document.querySelector('#b').addEventListener('click', (e) => {
      const newEvent = new e.constructor(e.type, e);
      document.querySelector('#a').dispatchEvent(newEvent);
    });
    <a id="a" href="https://wikipedia.org">google raw</a>
    <button id="b" type="button">click me while holding Ctrl on windows or Cmd on Mac</button>

    One issue is the event that passed in is "trusted" but the new event will not be "trusted". I don't know the implications.

    Note: I tried just dispatching the original event and got an error "event already dispatched". I could maybe use new PointerEvent instead of new e.constructor but a really old browser might send MouseEvent and maybe some new browser might send ARFingerEvent or something else.

    Update (it doesn't work)

    The implication of the event not being trusted (or maybe not) is that Firefox blocks the new tab from opening.

    So still looking for a solution. I guess I can hard code this to open the window myself in the click event (which I think is allowed) vs dispatching a new event. But, that's not the solution I wanted since I don't know what will change in the future.

    Further, it's OS specific. Technically, to be correct I'd need to do

    const a = document.querySelector('#a').click();
    if (osIsMac() && e.metaKey) {
      openInNewTab(a.href);
    } else (e.ctrlKey) {
      openInNewTab(a.href);
    } else {
      a.click();
    }
    

    But there's no guarantee that's correct for every OS. I settled on

    document.querySelector('#b').addEventListener('click', (e) => {
      const a = document.querySelector('#a');
      if (e.metaKey || e.ctrlKey) {
        e.preventDefault();
        window.open(a.href, '_blank');
      } else {
        a.click();
      }
    });
    <a id="a" href="https://wikipedia.org">google raw</a>
    <button id="b" type="button">click me while holding Ctrl on windows or Cmd on Mac</button>

    But even that doesn't work in the snippet above. It gets the error

    js:18 Blocked opening 'https://wikipedia.org/' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.

    Where as Ctrl/Cmd clicking the link itself works.

    Still looking for a generic "pass this event to a different element" solution.


  2. All that is need is to test for e.ctrlKey in your event handler.

    EDIT: If you want it to open in a new tab then add target="_blank" in your a tag. i.e.

    <a target="_blank" id="a" href="https://wikipedia.org">google raw</a>
    

    Which makes the snippet not work here, but will work in your browser.

    document.querySelector('#b').addEventListener('click', (e) => {
      if( e.ctrlKey ) document.querySelector('#a').click();
    });
    <a id="a" href="https://wikipedia.org">google raw</a>
    <button id="b" type="button">click me while holding Ctrl on windows or Cmd on Mac</button>
    Login or Signup to reply.
  3. The easiest solution to set target attribute conditionally.

    document.querySelector('#b').addEventListener('click', (e) => {
      const link = document.querySelector('#a')
      
      // check whether click event has ctrlKey(for windows) or metaKey(for mac) property
      if (e.ctrlKey || e.metaKey) {
        link.setAttribute('target', '_blank')
      }
      document.querySelector('#a').click();
      
      link.setAttribute('target', '_self')
    });
    

    It works, I check on codepen.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search