-1

I want to prevent default behavior of a link (a) then do the default behavior, let's say open open a link in a new window.

Here is some HTML code:

<a href="somewhere" target="_blank" id="mylink">

And the JS code:

document.getElementById('mylink').addEventListener('click', function (e) {
    e.preventDefault();
    axios.post('options', new FormData(document.querySelector('#myform')))
         .then(function(){ 
             // Here I want to do what the link should have done!
         });
});

I know I can do something like this:

window.open(e.target.href);

But it's not an option because the browser consider this as a popup. And I don't want to rewrite something in JS, just consider the link as usual: this link has to do its default behavior (which was prevented).

Is there a way to do this?

halfer
  • 19,824
  • 17
  • 99
  • 186
rap-2-h
  • 30,204
  • 37
  • 167
  • 263
  • 1
    what about `window.location = somewhere` ? – Doug May 23 '18 at 12:55
  • You can retrigger the click event of the link with setting and checking a flag. – Taha Paksu May 23 '18 at 12:55
  • @Doug: no, it's not what the HTML should ave done: the HTML (if default was not prevented) should have opened the link in a new window – rap-2-h May 23 '18 at 12:56
  • Possible duplicate of [What is the opposite of evt.preventDefault();](https://stackoverflow.com/questions/5651933/what-is-the-opposite-of-evt-preventdefault) – Alex May 23 '18 at 12:59
  • @TahaPaksu not sure to understand. Could you be more precise – rap-2-h May 23 '18 at 12:59
  • Possible duplicate of [Open a URL in a new tab (and not a new window) using JavaScript](https://stackoverflow.com/questions/4907843/open-a-url-in-a-new-tab-and-not-a-new-window-using-javascript) – Electrox Qui Mortem May 23 '18 at 13:01
  • Wrote an answer. – Taha Paksu May 23 '18 at 13:03
  • Is the result of opening this link dependent on the AJAX request? Meaning, _must_ it happen before, so that when the link is opened appropriate data is available server-side? – CBroe May 23 '18 at 13:37
  • @CBroe Yes! Exactly! – rap-2-h May 23 '18 at 13:43
  • 1
    This seems slightly like a XYProblem perhaps? If you are not suppose to execute the link unless an ajax event is successful (data available), it seems the link might not be the place to trigger the request to begin with. Your ajax call seems to use nothing from the link and there is nothing preventing the ajax call to be made when the page is loaded enabling or disabling the link to begin with. It seems you are also trying to work-around user preferences. As you said yourself `windows.open` would work but only if it wasn't opening popup,..which is user preferences. – Nope May 23 '18 at 13:44
  • One common workaround would be to open a popup first (when this happens _directly_ upon the user clicking the link, then it doesn’t get blocked in default settings in major browsers; the “empty page” `about:blank` is often used in such a situation), and then change the popup’s location in the callback. – CBroe May 23 '18 at 13:46
  • @halfer OK, thank you, and sorry for the edit! BTW there is a real problem on SO: you can mark as duplicate super-easily just by reading it quickly (I have this "power" too, so I saw how it could work). In that case, this was not a duplicate, and I was tired (if I remember well) to have the obligation to explain why it's not the same as a random other one, when the "closers" don't have too (just pointing to a link). So maybe a problem about SO, not the reviewer. Anyway, editing and down-voting in the same time can be "understood as hostile" too. I will avoid this kind of edit, again, sorry. – rap-2-h Sep 02 '18 at 08:26
  • Yes, there is an ethical bind: if I tell someone their response could be perceived as hostile, my intervention itself can be labelled as hostile, in whatever fashion I do it. However, I think the benefit of raising it outweighs the drawbacks in this sort of case, and I am robust enough to weather the counter-accusation. No hostility is intended, for what that assurance is worth `:-]` – halfer Sep 02 '18 at 10:22
  • "So maybe a problem about SO" - I am neutral on that question, but you're welcome to write up a proposal for _Meta_ if you have the time and energy for it. In my view you'd have to have a proposal about how it _should_ be done, rather than just that it should not be done; closing questions is an important quality mechanism here. – halfer Sep 02 '18 at 10:25

3 Answers3

0

Here is some idea:

var openingPopup = false;
document.getElementById('mylink').addEventListener('click', function (e) {
    if(!openingPopup){
        e.preventDefault();
        axios.post('options', new FormData(document.querySelector('#myform')))
            .then(function(){ 
                // make sure this would not run twice
                openingPopup = true;
                document.getElementById('mylink').click();
            });
    }else{
        // skipping this only for one time
        openingPopup = false; 
    }
});

This way,

  1. you run the popup opener click handler once,
  2. then prevent the others,
  3. trigger the click event again manually,
  4. this time do nothing, but allow others to run.
Taha Paksu
  • 15,371
  • 2
  • 44
  • 78
0

As per @Electrox-Qui-Mortem 's suggested link, after you complete your pre-process(es), you can remove the event listener and call the click again.

(relevant MDN link: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener )

const anchor = document.getElementById('anchor');

anchor.addEventListener('click', test);

function test(e){
  e.preventDefault();
  alert('test');
  if( true ){
    console.log( this );
    this.removeEventListener('click', test);
    this.click();
  }
}
<a id="anchor" href="https://www.google.com">Test</a>

It's got wonky performance inside code testing tools (like JSfiddle and CodePen) -- you would have to test it in your actual application to make sure if it works appropriately for your use case.

I've only had good results with removeEventListener when referencing an outside function as the "listener" func. In this case test()

Doug
  • 1,435
  • 1
  • 12
  • 26
  • Ok thank you for your answer. It does not work as excepted: it is considered as a unwanted popup. So it's not the same behavior: the link (without JS) works without browser prompt about popup, but with the triggered click, it's considered as an unwanted popup. (not sure I'm totally clear though) – rap-2-h May 23 '18 at 13:22
  • 2
    @rap-2-h this rather _has to_ be considered an unwanted popup - if it wasn’t, then shady advertisers would use the same method to get their popups past your popup blocker. – CBroe May 23 '18 at 13:35
0

In a more "native" way you could create a new "click" event which is not cancelable and trigger it against the same element.

var anchor = document.querySelector('#target');

function triggerClick(target) {
  var newClick = new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: false
  });
  
  target.dispatchEvent(newClick);
}

anchor.addEventListener('click', function(e) {
  e.preventDefault();
  
  if(e.defaultPrevented) {
    alert('Prevented!');
    triggerClick(anchor);
  }
  else {
    alert('Not prevented');
  }
});
<a href="https://google.com" target="_blank" id="target">Click me!</a>

Here the key is the cancelable: false in the new event created in the function triggerClick(target), which bypass the e.preventDefault().

In the embedded example on StackOverflow it doesn't work, but here's a JSFiddle!

dgopsq
  • 144
  • 5
  • Thank you, it works, BUT it does not work if my triggerClick function is inside a callback (just like in my question). It displays a popup information (popup was blocked, blablabla) – rap-2-h May 23 '18 at 13:35
  • @rap-2-h Are you sure you are not doing something else which could interfere inside the callback? I tried with an HTTP request in this [Fiddle](https://jsfiddle.net/mx0s8brh/1/) and it seems to work for me. – dgopsq May 23 '18 at 13:50