Home > Mobile >  Don't fire mouseenter event on parent
Don't fire mouseenter event on parent

Time:10-14

For tags (td, p, li) that contain text, I added a data-id attribute. When hovering over a tag that has a data-id attribute, the button needs to be displayed. Everything works fine, except when the tags are nested, for example:

<li aria-level="1" data-id="66389178">
  <p data-id="11168609">text</p>
</li>

This example displays two buttons, one for the parent and one for the child. I added e.stopImmediatePropagation(); but that doesn't work for td. Here is the code itself:

$('[data-id]').mouseenter(function (e) {
  GodObj.btnadd = $('<button class="btn btn-outline-dark btn-note-tag">'  
    '<i class=\'fa fa-commenting\' aria-hidden=\'true\'></i>'   '</button>');

  $(this).append(GodObj.btnadd);
  e.stopImmediatePropagation();
}).mouseleave(function () {
  $(GodObj.btnadd).remove();
});

Example when two buttons are drawn:

<td aria-level="1" data-id="66389170">
  <p data-id="11168601">...</p>
</td>

Content is added by users through the editor on the site, so there is no strict rule for the level of nesting of tags into each other.

How to make the button render only once or for parent or child elements?

CodePudding user response:

You need to start with e.stopImmediatePropagation();:

            $('[data-id]').mouseenter(function (e) {
                e.stopImmediatePropagation();
                GodObj.btnadd = $('<button class="btn btn-outline-dark btn-note-tag">'  
                    '<i class=\'fa fa-commenting\' aria-hidden=\'true\'></i>'  
                    '</button>');
                $(this).append(GodObj.btnadd);
            }).mouseleave(function () {
                $(GodObj.btnadd).remove();
            });

CodePudding user response:

I took the approach where it only appends the button to the top level element with the data-id attribute. First by checking the parents:

var target = $(this).parents('[data-id]').last();

If this collection is empty (zero length) then the current element is the top level one:

if (!target.length) target = $(this);

Another tricky bit was the part where it creates a new jQuery object on each mouseenter event:

GodObj.btnadd = $(...

This meant that when you enter a child element with the data-id attribute, the original object is replaced with a new instance and it's no longer possible to use this part because it refers to another object:

GodObj.btnadd.remove();

So I added a condition:

if (!GodObj.btnadd)

Another option would be to define the variable outside the event listener.

I've put the mouseleave event listener inside the mouseenter which isn't exactly essential but it might make the code clearer. Important thing to always do in such a case is using .one so the listener gets removed afterwards and doesn't accumulate on each mouseenter event.

https://api.jquery.com/one

var GodObj = {};

$('[data-id]').mouseenter(function() {

  if (!GodObj.btnadd) GodObj.btnadd = $('<button class="btn btn-outline-dark btn-note-tag">'  
    '<i class=\'fa fa-commenting\' aria-hidden=\'true\'></i>'   '</button>');

  var target = $(this).parents('[data-id]').last();
  if (!target.length) target = $(this);
  target.append(GodObj.btnadd);

  target.one('mouseleave', function() {
    GodObj.btnadd.remove();
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table>
  <tr>
    <td aria-level="1" data-id="66389170">
      <p data-id="11168601">...</p>
    </td>
  </tr>
</table>

  • Related