2

I have two divs with dynamic links that sometimes are populated and sometimes aren't. If you a click a link that looks like this:

<a href="#">

Nothing happens, I prevent the default action, but if the link is:

<a href="/path/to/a/page">

It will follow.

I want to able to click on the surrounding div, and using the same logic as above. So if I click on the red and there is a valid link the link will follow. I'm using trigger() to attempt this.

The situation is below:

$(function() {
 $(".container").click(function(e) {
    var clickTarget = $(e.target).attr("href");
    var clickTargetLink = $(this).find(".container-link");
      if ((clickTarget != "#") || (clickTarget != undefined)) {
        clickTargetLink.trigger("click");
      } else {
        e.preventDefault();
      }
  });
});
.container {
  padding: 50px;
  margin-bottom: 1rem;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="google.com">link</a>
</div>
<div class="container">
  <a class="container-link" href="#">link</a>
</div>

What ends up happening is clicking on the red div with google.com in the link throws:

jquery.js:3988 Uncaught RangeError: Maximum call stack size exceeded at String.replace () at camelCase (jquery.js:3988) at Data.get (jquery.js:4069) at HTMLDivElement.dispatch (jquery.js:5146) at HTMLDivElement.elemData.handle (jquery.js:4991) at Object.trigger (jquery.js:8249) at HTMLAnchorElement. (jquery.js:8327) at Function.each (jquery.js:354) at jQuery.fn.init.each (jquery.js:189) at jQuery.fn.init.trigger (jquery.js:8326)

Maximum call stack size exceeded error - this suggests that there is an infinity loop somewhere in this code. I'm lost as to how that could be the case here?

Why is this code causing a maximum call stack size error?

EDIT: more research led me to: Maximum call stack size exceeded on trigger click

going

.triggerHandler() just renders nothing and the link doesn't follow. Is there a different action I need to use that I'm not aware of?

EDIT #2: a few more details:

  1. I cannot change/add markup structure.
  2. the red div needs to be fully clickable, as there is another action tied to it when the link is empty: <a href="#">
  3. I tried e.stopPropagation(); - which resolves the error, but then the link doesn't follow
  4. I tried triggerHandler() - http://api.jquery.com/triggerhandler/
kawnah
  • 3,204
  • 8
  • 53
  • 103
  • 6
    Your click handler triggers a click event, which is handled by the click handler, which triggers a click event, which... – Daniel Beck Aug 15 '18 at 13:43
  • Check the browser console, it says `too much recursion` (in Firefox). You are firing the click event recursively – przno Aug 15 '18 at 13:45

6 Answers6

2

Your click handler is triggering a new click event, which is handled by the click handler, which triggers a new click event, which is handled by the click handler, which... eventually overflows the stack.

In comments (and now in the updated question) you've clarified the purpose of this code:

The red area needs to be clickable, not just the link. That's why I'm trying to use .trigger() so that I can trigger a click in the child link inside the div when the div is clicked on.

This necessitates a few more changes beyond just fixing your infinite loop:

  • Your existing code was looking for the href on the event target itself, which would not have allowed the red area to be clickable (because the event target isn't necessarily the element with an href attribute). I've changed this to ignore the event target (which isn't really what you care about) and instead just pluck the href from the link inside the container element.

  • In your if clause you used || when you meant && ("if it's not X or it's not Y" will always be true; "if it's not X and it's not Y" is what you meant there.)

The infinite recursion is resolved here by simply setting the window location directly, rather than firing another click event.

$(function() {
  $(".container").click(function(e) {
    var clickTarget = $(this).find("a.container-link").attr("href");
    if (clickTarget && clickTarget !== "#") {
      window.location=clickTarget;
    } else {
      // prevent link navigation from occurring
      console.log("Blocking click");
      e.preventDefault();
    }
  });
});
.container {
  padding: 10px;
  margin-bottom: 1rem;
  background-color: red;
  cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="https://example.com">Normal link</a>
</div>
<div class="container">
  <a class="container-link" href="#">Blocked link</a>
</div>
Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
2

You could optionally check to see if it is the link or the container that was clicked. If it was the link, do not trigger another click.

$(function() {
  $(".container").click(function(e) {
    var $containerLink = $(this).find('.container-link');
    //check to see if the container was clicked, or if the link was clicked
    var linkWasClicked = $(e.target).is('.container-link');
    
    if (['#', undefined].indexOf($containerLink.attr('href')) > -1) {
      e.preventDefault();
    } else if (!linkWasClicked) { //only trigger the link if it was not clicked
      $containerLink[0].click();
    }
  });
});
.container {
  padding: 50px;
  margin-bottom: 1rem;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="https://google.com">link</a>
</div>
<div class="container">
  <a class="container-link" href="#">link</a>
</div>
Taplar
  • 24,788
  • 4
  • 22
  • 35
1

When the container is clicked, you trigger a click on the link inside it which propagates back to the container, clicking on the link again, and so on. You are recursively clicking on the link over and over again, which is causing the error. In your click event handler for the container, you need to check if the event's currentTarget is equal to the event's target to click on the link (preventing recursion). To trigger the click on the link to redirect to another page, you will need to get the actual DOM element to click on (not the jQuery object) like this: clickTargetLink[0].click() (jQuery always returns an Array of elements).

.container {
  padding: 50px;
  margin-bottom: 1rem;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <a class="container-link" href="http://www.example.com">link</a>
</div>
<div class="container">
  <a class="container-link" href="#">link</a>
</div>
<script>
$(function() {
 $(".container").click(function(e) {
    var clickTarget = $(e.target).attr("href");
    var clickTargetLink = $(this).find(".container-link");
      if (e.currentTarget==e.target) {
        clickTargetLink[0].click();
      } else {
       if(clickTarget!==undefined&&clickTarget == "#"){
       e.preventDefault();
       }
      }
  });
});
</script>
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
0

Because .container-link is inside .container the click event of the .container-link triggers a click also for .container unless you do stopPrpogation(), what causes the infinite loop.

Use stopPropagation() inside the if (after triggering the click).

Programmer
  • 1,973
  • 1
  • 12
  • 20
  • I'm still seeing `Maximum call stack size exceeded` even after using `stopPropagation()` after the trigger event. – kawnah Aug 15 '18 at 13:56
0

as you can see in comments you are triggering click in the handler for the click which is causing to go in a loop . click-> handler-> trigger click-> handler --->

so basically attach handler to link itself, or if you want to attach it to parent only check if the target is link

you can also look at this thread for more breadth on topic In jQuery, how can I tell between a programmatic and user click?

ashish singh
  • 6,526
  • 2
  • 15
  • 35
0

Just improve your JS this way:

$(function () {
  $(".container").click(function (e) {
    var clickTarget = $(e.target).attr("href");
    var clickTargetLink = $(this).find(".container-link");
    if ((clickTarget === "#") || (clickTarget === undefined)) return false
  })
})
Vladislav Ladicky
  • 2,261
  • 1
  • 11
  • 13