Taylor1978
Taylor1978

Reputation: 13

Get data attribute from targeted .on() jQuery

I am having some difficulty with .on() and getting the data-id of a targeted element.

$("#updateTables-0").on(".joinTable").click(function() {

  var tableID = $(".joinTable").attr('data-id');
  console.log(tableID);

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <span id='updateTables-0'>
        <li class="list-group-item joinTable" data-id='2' data-toggle="modal" data-target="#tableConnect" >
            <div class="users-list-body">
                <div>
                    <h5 class="text-primary">100 pt | Regular</h5>
                    <p>vs. DeadSaidFred [1500]</p>
                </div>
                <div class="users-list-action">
                    <div class="new-message-count" title='Table #4'>4</div>
                </div>
            </div>
        </li>
        <li class="list-group-item joinTable" data-id='3' data-toggle="modal" data-target="#tableConnect" >
            <div class="users-list-body">
                <div>
                    <h5 class="text-primary">100 pt | Regular</h5>
                    <p>vs. coronatime [1500]</p>
                </div>
                <div class="users-list-action">
                    <div class="new-message-count" title='Table #5'>5</div>
                </div>
            </div>
        </li>
    </span>
</ul>

As you can see I have two li list items, one with a data-id of 2 and one of 3. No matter which one I click, it is only returning the first.

If I was not using $("#updateTables-0").on() and just instead had $(".joinTable") I could call $(this) and it would work perfectly. (Note, using $(this) for my actual example above with .on() returns undefined.)

I am using the .on() as the list updates via web sockets, and so I need to have it listening to any changes. Without, once the list updates via the socket, the function won't work at all.

Any help appreciated.

Upvotes: 1

Views: 126

Answers (3)

David Thomas
David Thomas

Reputation: 253328

As event delegation is required, and your current HTML is invalid – the only valid child of either a <ul> or <ol> element is the <li> – I've delegated the event-handling to the parent <ul> element (and attached the id to that element also). This may need to change for your use-case, however; so please do comment if so.

In this case, however, to stick with the jQuery approach the following code works:

// bear in mind that this id now selects the parent <ul>
// we attach the anonymous function as the 'click' event-handler
// of click-events that match the '.joinTable' selector:
$("#updateTables-0").on('click', '.joinTable', function(event) {
  // here we use the 'this' Node (the node we bound the event-
  // handler to, and retrieve its 'data-id' attribute value
  // with the data() method:
  const tableID = $(this).data('id');
  console.log(tableID);
});

$("#updateTables-0").on('click', '.joinTable', function() {
  const tableID = $(this).data('id');
  console.log(tableID);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<ul id='updateTables-0'>
  <li class="list-group-item joinTable" data-id='2' data-toggle="modal" data-target="#tableConnect">
    <div class="users-list-body">
      <div>
        <h5 class="text-primary">100 pt | Regular</h5>
        <p>vs. DeadSaidFred [1500]</p>
      </div>
      <div class="users-list-action">
        <div class="new-message-count" title='Table #4'>4</div>
      </div>
    </div>
  </li>
  <li class="list-group-item joinTable" data-id='3' data-toggle="modal" data-target="#tableConnect">
    <div class="users-list-body">
      <div>
        <h5 class="text-primary">100 pt | Regular</h5>
        <p>vs. coronatime [1500]</p>
      </div>
      <div class="users-list-action">
        <div class="new-message-count" title='Table #5'>5</div>
      </div>
    </div>
  </li>
</ul>

This can, as can all jQuery approaches, be rewritten into plain native JavaScript:

// here we use document.querySelector() to retrieve the
// HTMLElement Node that matches the CSS selector:
const delegationTarget = document.querySelector('#updateTables-0');

// here we use addEventListener() to bind the anonymous
// Arrow function as the event-handler for the 'click'
// event:
delegationTarget.addEventListener('click', (evt) => {
  // using evt.target to find the element upon which
  // the click event was initially fired; using
  // closest() to navigate to the ancestor <li>
  // of that clicked-element; and using the
  // HTMLElement.dataset API to recover the attribute-
  // value of the 'id' property (or to recover the
  // attribute-value of the data-id attribute, if you
  // prefer):
  const tableID = evt.target.closest('li').dataset.id;
  console.log(tableID);
});

const delegationTarget = document.querySelector('#updateTables-0');

delegationTarget.addEventListener('click', (evt) => {
  const tableID = evt.target.closest('li').dataset.id;
  console.log(tableID);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<ul id='updateTables-0'>
  <li class="list-group-item joinTable" data-id='2' data-toggle="modal" data-target="#tableConnect">
    <div class="users-list-body">
      <div>
        <h5 class="text-primary">100 pt | Regular</h5>
        <p>vs. DeadSaidFred [1500]</p>
      </div>
      <div class="users-list-action">
        <div class="new-message-count" title='Table #4'>4</div>
      </div>
    </div>
  </li>
  <li class="list-group-item joinTable" data-id='3' data-toggle="modal" data-target="#tableConnect">
    <div class="users-list-body">
      <div>
        <h5 class="text-primary">100 pt | Regular</h5>
        <p>vs. coronatime [1500]</p>
      </div>
      <div class="users-list-action">
        <div class="new-message-count" title='Table #5'>5</div>
      </div>
    </div>
  </li>
</ul>

References:

Upvotes: 1

Juan Marco
Juan Marco

Reputation: 3241

You're using a <span> as a direct child element of the <ul>, this is invalid HTML. To fix this, you could assign the id directly to the <ul> element:

  <ul id='updateTables-0'>
    <li class="list-group-item joinTable" data-id='2' data-toggle="modal" data-target="#tableConnect">
      <div class="users-list-body">
        <div>
          <h5 class="text-primary">100 pt | Regular</h5>
          <p>vs. DeadSaidFred [1500]</p>
        </div>
        <div class="users-list-action">
          <div class="new-message-count" title='Table #4'>4</div>
        </div>
      </div>
    </li>
    <li class="list-group-item joinTable" data-id='3' data-toggle="modal" data-target="#tableConnect">
      <div class="users-list-body">
        <div>
          <h5 class="text-primary">100 pt | Regular</h5>
          <p>vs. coronatime [1500]</p>
        </div>
        <div class="users-list-action">
          <div class="new-message-count" title='Table #5'>5</div>
        </div>
      </div>
    </li>
  </ul>

And then use event delegation to capture each <li> of the unordered list:

$("#updateTables-0").on("click", "li", function() {
  const $li = $(this)
  console.log(`data-id of list item: ${ $li.attr('data-id') }`)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id='updateTables-0'>
  <li class="list-group-item joinTable" data-id='2' data-toggle="modal" data-target="#tableConnect">
    <div class="users-list-body">
      <div>
        <h5 class="text-primary">100 pt | Regular</h5>
        <p>vs. DeadSaidFred [1500]</p>
      </div>
      <div class="users-list-action">
        <div class="new-message-count" title='Table #4'>4</div>
      </div>
    </div>
  </li>
  <li class="list-group-item joinTable" data-id='3' data-toggle="modal" data-target="#tableConnect">
    <div class="users-list-body">
      <div>
        <h5 class="text-primary">100 pt | Regular</h5>
        <p>vs. coronatime [1500]</p>
      </div>
      <div class="users-list-action">
        <div class="new-message-count" title='Table #5'>5</div>
      </div>
    </div>
  </li>
</ul>

Upvotes: 0

Jakub Kriz
Jakub Kriz

Reputation: 1529

Use $(this)

Use jQuery's inner $(this) object inside click callback.

$("#updateTables-0 .joinTable").on("click",function() {

   var tableID = $(this).attr('data-id');
   console.log(tableID);

});

Good reading about this topic

https://medium.com/@sak1986/event-binding-in-jquery-daf902be7c58

Upvotes: 1

Related Questions