0

I want to record down the full css path on every element click by user, I follow this answer to create a function that get css path of the clicked element

$('body').on('click',"*",function(){
    var rightArrowParents = [];
    $(this).parents().addBack().not('html').each(function(e) {
        var entry = this.tagName.toLowerCase();

        if($(this).attr('id')){
            entry += "#" + $(this).attr('id');
        }

        if (this.className) {
        entry += "." + this.className.replace(/ /g, '.');
        }

        rightArrowParents.push(entry);
    });
    console.log(rightArrowParents.join(" > "));
})

but I notice that this function is called so many times when I click on an element which is wrap by multiple element,

for example when I click on h1:

body > div.sample1.sample2 > div.sample3.sample4 > h1.test1.test2.test3

body > div.sample1.sample2 > div.sample3.sample4

body > div.sample1.sample2

when I add return false after console.log, it will only output the full css path of h1, which is the expected result, but if I do this, some element will not work properly such as <a> will not redirect to another website

below is what I have tried:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <title>Document</title>
</head>
<body>
    <div class="sample1 sample2">
        <div class="sample3 sample4">
            <h1 class="test1 test2 test3">some example text</h1>
        </div>
    </div>
    <div>
        <h1 class="test1 test2 test3">some sample text</h1>
    </div>
    <div class="sample1 sample2">
        <div class="sample3 sample4">
            <a class="test1 test2 test3" href="https://www.google.com/">henlo</a>
        </div>
    </div>
    <script>
        jQuery(function($){
            $('body').on('click',"*",function(){
                var rightArrowParents = [];
                $(this).parents().addBack().not('html').each(function(e) {
                    var entry = this.tagName.toLowerCase();

                    if($(this).attr('id')){
                        entry += "#" + $(this).attr('id');
                    }

                    if (this.className) {
                    entry += "." + this.className.replace(/ /g, '.');
                    }

                    rightArrowParents.push(entry);
                });
                console.log(rightArrowParents.join(" > "));
                //can't do this, since it will make some element malfunction
                //return false
            })
        })
    </script>
</body>
</html>

what should I do to make the jQuery work properly?

jiale ko
  • 139
  • 1
  • 13
  • 1
    This is because of _event propagation_ which is a standard feature of jQuery. jQuery is, in fact, working as it should. You can read more about event propagation (including how to resolve your issue) here: https://learn.jquery.com/events/event-delegation/ – Martin Feb 14 '20 at 08:32

2 Answers2

2

If I understand your question clearly, all you need to do is add an event parameter to your function function(e), then use e.stopPropagation() at the end to prevent it from going through the event handlers of the parent elements.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <title>Document</title>
</head>

<body>
  <div class="sample1 sample2">
    <div class="sample3 sample4">
      <h1 class="test1 test2 test3">some example text</h1>
    </div>
  </div>
  <div>
    <h1 class="test1 test2 test3">some sample text</h1>
  </div>
  <div class="sample1 sample2">
    <div class="sample3 sample4">
      <a class="test1 test2 test3" href="https://www.google.com/">henlo</a>
    </div>
  </div>
  <script>
    jQuery(function($) {
      $('body').on('click', "*", function(e) {
        var rightArrowParents = [];
        $(this).parents().addBack().not('html').each(function() {
          var entry = this.tagName.toLowerCase();

          if ($(this).attr('id')) {
            entry += "#" + $(this).attr('id');
          }

          if (this.className) {
            entry += "." + this.className.replace(/ /g, '.');
          }

          rightArrowParents.push(entry);
        });
        console.log(rightArrowParents.join(" > "));
        
        e.stopPropagation();
      })
    })
  </script>
</body>

</html>
Dumisani
  • 2,988
  • 1
  • 29
  • 40
1

This solution may look a bit hacky, but it gets the job done. along these lines there may also be a more elegant solution (like to compare some property of the event for cancellation.

jQuery(function($){
    $('body').on('click',"*",function(e) {
        // mark the event as seen and cancel it it was seen
        if (e.seen) return;
        e.seen = true;
        
        var rightArrowParents = [];
        $(this).parents().addBack().not('html').each(function(i, o) {
            var entry = this.tagName.toLowerCase();

            if($(this).attr('id')){
                entry += "#" + $(this).attr('id');
            }

            if (this.className) {
            entry += "." + this.className.replace(/ /g, '.');
            }

            rightArrowParents.push(entry);
        });
        console.log(rightArrowParents.join(" > "));
    })
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <title>Document</title>
</head>
<body>
    <div class="sample1 sample2">
        <div class="sample3 sample4">
            <h1 class="test1 test2 test3">some example text</h1>
        </div>
    </div>
    <div>
        <h1 class="test1 test2 test3">some sample text</h1>
    </div>
    <div class="sample1 sample2">
        <div class="sample3 sample4">
            <a class="test1 test2 test3" href="https://www.google.com/">henlo</a>
        </div>
    </div>
</body>
</html>
ZPiDER
  • 4,264
  • 1
  • 17
  • 17