Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery and id selector issue

I have a need to generate random id's for some buttons created on the page. I create the buttons using this jquery:

var btnId = 'delete-' + row.id;
$("<button/>", {
    'id': btnId,
    'html': $("<i></i>").addClass("ion-icon ion-btn ion-trash-a"),
    'class': 'btn btn-primary btn-md'
}).append(' Delete')

The template for the button id's:

delete-$UUID, where $UUID is retrieved from a database.

This worked well, and after creating, I was able to even attach a click listener to each button using jquery:

$('button#' + btnId).click(function(e) { alert("Button clicked!"); });

The plot thickens

Now, I decided not to use the database row id, but instead generate a random string to use as the button id's, so I created this function:

function _randomString (min, max) {
    var text = "";
    var length = Math.floor(Math.random() * (max - min) + min);
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz0123456789";
    for (var i = 0; i < length; i++) {
        text += possible.charAt(Math.floor(Math.random() * possible.length));
    }
    return text;
}

, Then replaced the button id like this

var btnId = 'delete-' + _randomString(20, 30);

As you can see, the only thing different is that the $UUID is replaced by the value of this function I created.

The climax

Now when I use jquery to add a click listener (the same jquery as above), the bind stopped working with jquery. No matter what happens, jquery does not seem to want to find and bind the click listener to the buttons when created with such an id.

At first, I thought this may be due to the function not generating random strings, but I went to the console and I took the generated id of one of the buttons, and when I did $('copied-button-id').length, I got 1. So obviously, jquery is able to find the button now, but not when it was created as was the case when I used the database row id to create the button id.

Even stranger is that when I remove that randomly generated string and replace it with a plain string like sdfsdfsd, i.e. now all the buttons have the id delete-sdfsdfsd, jquery has no problem finding and binding to the buttons.

Before anyone asks, I have also perused the acceptable ids for html elements, so this is not an issue. What are valid values for the id attribute in HTML?

Resolution

Here is where I need your help. I guess I'm either really tired or something, but can you look at my function and tell me what may be causing this issue. I've eliminated length issue, as I've been able to use ids of length in excess of 60 characters and they all worked. Is JQuery exhibiting undefined behavior by being able to find (or not) any of the buttons created in this way? Am I exhibiting undefined behaviour? What am I missing?

Any help is welcome!


JQuery version: 2.1.4

MCVE:

$(function() {
  var numRows = 10;
  var $table = $('#db-table');
  for (var i = 0; i < numRows; i++) {
    $table.find('tbody').append("<tr/>");
    var name = _randomString(5, 10);
    var age = Math.floor(Math.random() * 25 + 5);
    var $row = $table.find('tbody tr:eq(' + i + ')');
    $row.append($("<td/>", {
      html: "<span>" + name + "</span>"
    })).append($("<td/>", {
      html: "<span>" + age + "</span>"
    })).append(_getButton({
      id: _randomString(20, 30)
    }));
  }
});

function _randomString(min, max) {
  var text = "";
  var length = Math.floor(Math.random() * (max - min) + min);
  var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz0123456789";
  for (var i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
}

function _getButton(row) {
  var btnId = 'delete-' + row.id;
  var $btn = $("<button/>", {
    'id': btnId,
    'html': $("<i></i>").addClass("ion-icon ion-btn ion-trash-a"),
    'class': 'btn btn-primary btn-md'
  }).append(' Delete');

  $('button#' + btnId).click(function(e) {
    alert("You clicked a button!!");
  });

  return $btn.prop('outerHTML');
}
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<div class="container">
  <div class="row">
    <table id="db-table" class="table-responsive">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
  </div>
</div>
like image 330
smac89 Avatar asked Jun 04 '26 13:06

smac89


2 Answers

You're using the selector $("button#' + btnId) in the _getButton() function. But the button isn't appended to the DOM until the function returns and the button is passed to $row.append().

Instead, just bind to the element itself, rather than using a selector. And _getButton() needs to return the element itself, not its outerHTML, because that will lose the event binding.

$(function() {
  var numRows = 10;
  var $table = $('#db-table');
  for (var i = 0; i < numRows; i++) {
    $table.find('tbody').append("<tr/>");
    var name = _randomString(5, 10);
    var age = Math.floor(Math.random() * 25 + 5);
    var $row = $table.find('tbody tr:eq(' + i + ')');
    $row.append($("<td/>", {
      html: "<span>" + name + "</span>"
    })).append($("<td/>", {
      html: "<span>" + age + "</span>"
    })).append(_getButton({
      id: _randomString(20, 30)
    }));
  }
});

function _randomString(min, max) {
  var text = "";
  var length = Math.floor(Math.random() * (max - min) + min);
  var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz0123456789";
  for (var i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
}

function _getButton(row) {
  var btnId = 'delete-' + row.id;
  var $btn = $("<button/>", {
    'id': btnId,
    'html': $("<i></i>").addClass("ion-icon ion-btn ion-trash-a"),
    'class': 'btn btn-primary btn-md'
  }).append(' Delete');

  $btn.click(function(e) {
    alert("You clicked a button!!");
  });

  return $btn;
}
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<div class="container">
  <div class="row">
    <table id="db-table" class="table-responsive">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
  </div>
</div>
like image 104
Barmar Avatar answered Jun 07 '26 23:06

Barmar


It seems really unnecessary to use an ID at all for this. Just use a CSS class, bind your click event to all buttons with that class, and if you need to do something specific to a row or data associated with that button, use html5 data tags on the element, or just use $(this).find(...) or $(this).closest(...) to get whatever information you need when the button is clicked.

Again, not 100% clear on the use case here, but just for the sake of example, let's say your button class is awesome-button:

// Using $(document).on('click') instead of just
// $('.awesome-button').click() since you seem to be dynamically creating buttons.

$(document).on('click', '.awesome-button', function() {
  var row = $(this).closest('tr');

  // Now do whatever you want with the row...
  row.find('.something-obscure');

  // Or maybe your rows have data tags on them that need to go somewhere?
  someCrazyFunction(row.data('example'));

  // etc...
});
like image 41
Ben Fried Avatar answered Jun 07 '26 23:06

Ben Fried



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!