skip to Main Content

I tried to update values in a table using jQuery. I want that when I click ‘update’ it changes the value and returns the form as it was. Also when i click ‘cancel’ it cancels the update. In my example it doesn’t work.

$(document).on('click', '.btn-edit', function(e) {
  var name = $(this).parents("tr").attr('data-name');
  var email = $(this).parents("tr").attr('data-email');
  $(this).parents("tr").find("td:eq(0)").html('<input name="edit_name" value="' + name + '">');
  $(this).parents("tr").find("td:eq(1)").html('<input name="edit_email" value="' + email + '">');
  $(this).parents("tr").find("td:eq(2)").prepend("<button class='btn btn-info btn-xs btn-update'>Update</button><button class='btn btn-warning btn-xs btn-cancel'>Cancel</button>")
  $(this).hide();
});

$(document).on('click', '.btn-update', function(e) {
  var name = $(this).parents("tr").attr('data-name');
  var email = $(this).parents("tr").attr('data-email');
  $(this).parents("tr").find("td:eq(0)").text(name);
  $(this).parents("tr").find("td:eq(1)").text(email);
  $(this).parents("tr").find(".btn-edit").show();
  $(this).parents("tr").find(".btn-update").remove();
  $(this).parents("tr").find(".btn-cancel").remove();
});

$(document).on('click', '.btn-cancel', function(e) {
  var name = $(this).parents("tr").find("input[name='edit_name']").val();
  var email = $(this).parents("tr").find("input[name='edit_email']").val();
  $(this).parents("tr").find("td:eq(0)").text(name);
  $(this).parents("tr").find("td:eq(1)").text(email);
  $(this).parents("tr").attr('data-name', name);
  $(this).parents("tr").attr('data-email', email);
  $(this).parents("tr").find(".btn-edit").show();
  $(this).parents("tr").find(".btn-cancel").remove();
  $(this).parents("tr").find(".btn-update").remove();
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>

<div class="container">
  <table class="table table-bordered ">
    <thead>
      <th>Name</th>
      <th>Email</th>
      <th width="200px">Action</th>
    </thead>
    <tbody>
      <tr data-name='marzouk najib' data-email='[email protected]'>
        <td>marzouk najib</td>
        <td>[email protected]</td>
        <td><button class='btn btn-info btn-xs btn-edit'>Edit</button></td>
      </tr>
    </tbody>
  </table>
</div>

4

Answers


  1. When creating a normal event listener, it is immediately tied to existing elements on the page. So dynamic elements won’t get the event listener.

    You can use delegation to solve the problem for the btn-update event listener use this instead:

    $(document).on('click','.btn-update', function(e) {
    
    Login or Signup to reply.
  2. You need to use delegated event handlers as you’re dynamically creating and removing the buttons.

    In addition your logic is not quite right. You need to update the data attributes on the tr when the ‘update’ button is clicked, not the ‘cancel’.

    The logic can also be improved by caching your selectors in variables instead of recreating them for each method call. In addition you can use closest() instead of parents() to get the nearest parent tr element, data() instead of attr() to read data attributes and also children() instead of find() to get the child td.

    With that said, try this:

    $(document).on('click', '.btn-edit', function(e) {
      let $tr = $(this).hide().closest('tr');
      $tr.children("td:eq(0)").html(`<input name="edit_name" value="${$tr.data('name')}">`);
      $tr.children("td:eq(1)").html(`<input name="edit_email" value="${$tr.data('email')}">`);
      $tr.children("td:eq(2)").prepend("<button class='btn btn-info btn-xs btn-update'>Update</button><button class='btn btn-warning btn-xs btn-cancel'>Cancel</button>")
    });
    
    $(document).on('click', '.btn-update', function(e) {
      let $tr = $(this).closest('tr');
      let name = $tr.find('[name="edit_name"]').val();
      let email = $tr.find('[name="edit_email"]').val();
      $tr.data({ name, email });
      $tr.children("td:eq(0)").text(name);
      $tr.children("td:eq(1)").text(email);
      $tr.find(".btn-edit").show();
      $tr.find(".btn-update, .btn-cancel").remove();
    });
    
    $(document).on('click', '.btn-cancel', function(e) {
      let $tr = $(this).closest('tr');
      $tr.children("td:eq(0)").text($tr.data('name'));
      $tr.children("td:eq(1)").text($tr.data('email'));  
      $tr.find(".btn-edit").show();
      $tr.find(".btn-update, .btn-cancel").remove();
    });
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    
    <div class="container">
      <table class="table table-bordered ">
        <thead>
          <th>Name</th>
          <th>Email</th>
          <th width="200px">Action</th>
        </thead>
        <tbody>
          <tr data-name='marzouk najib' data-email='[email protected]'>
            <td>marzouk najib</td>
            <td>[email protected]</td>
            <td><button class='btn btn-info btn-xs btn-edit'>Edit</button></td>
          </tr>
        </tbody>
      </table>
    </div>
    Login or Signup to reply.
  3. The problem is that you are setting event listeners for btn-cancel and btn-update when they are not existing yet, try to set the events just after create the buttons, or create the buttons and show/hide the cancel/update buttons.

    $('.btn-edit').on('click', function(e) {
        var name = $(this).parents("tr").attr('data-name');
        var email = $(this).parents("tr").attr('data-email');
        $(this).parents("tr").find("td:eq(0)").html('<input name="edit_name" value="'+name+'"/>');
        $(this).parents("tr").find("td:eq(1)").html('<input name="edit_email" value="'+email+'"/>');
        $(this).parents("tr").find("td:eq(2)").prepend("<button class='btn btn-info btn-xs btn-update'>Update</button><button class='btn btn-warning btn-xs btn-cancel'>Cancel</button>")
        $(this).hide();
    
        $('.btn-cancel').on('click', function(e) {
            var name = $(this).parents("tr").attr('data-name');
            var email = $(this).parents("tr").attr('data-email');
            $(this).parents("tr").find("td:eq(0)").text(name);
            $(this).parents("tr").find("td:eq(1)").text(email);
    
            $(this).parents("tr").find(".btn-edit").show();
            $(this).parents("tr").find(".btn-update").remove();
            $(this).parents("tr").find(".btn-cancel").remove();
        });
           
        $('.btn-update').on('click', function(e) {
            var name = $(this).parents("tr").find("input[name='edit_name']").val();
            var email = $(this).parents("tr").find("input[name='edit_email']").val();
              
            $(this).parents("tr").find("td:eq(0)").text(name);
            $(this).parents("tr").find("td:eq(1)").text(email);
            $(this).parents("tr").attr('data-name', name);
            $(this).parents("tr").attr('data-email', email);
            $(this).parents("tr").find(".btn-edit").show();
            $(this).parents("tr").find(".btn-cancel").remove();
            $(this).parents("tr").find(".btn-update").remove();
        });
    });
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
        <div class="container">
          <table class="table table-bordered ">
            <thead>
              <th>Name</th>
              <th>Email</th>
              <th width="200px">Action</th>
            </thead>
            <tbody>
              <tr data-name='marzouk najib' data-email='[email protected]'>
                <td>marzouk najib</td>
                <td>[email protected]</td>
                <td><button class='btn btn-info btn-xs btn-edit'>Edit</button></td>
              </tr>
            </tbody>
          </table>
        </div>
    Login or Signup to reply.
  4. Don’t need to explain myself like the rest have done by using event delegation
    on('click','.btn-update', function(e) {

    but i can give you some other suggestions:

    • you could register all click event on the table instead; leaving you with just one click event listener instead of register a click event on every edit button – this can give you a performance boost if you have many rows. and they all work for newly inserted/modified rows, even the edit button.
    • be carful when concatenating input values and using .html() they could embed javascript and other html tags by escaping the quotes. (look at how i solved it instead)
    • and you better not use $(document).on('click' it’s better to narrow it down to the table, otherwise the event listener will fire internally in jQuery’s core for every click you do outside of the table
    • you are using lots of $(this).parent('tr').find() this can be cached and reduce the the amount of work needed to query elements if you just cached the tr and used it as a selector container $('.class', tr) see how i solved it below
    $('table')
    .on('click', '.btn-edit', function(e) {
      const tr = $(this).parents("tr")[0]
      const { name, email } = tr.dataset
      $("td:eq(0)", tr).empty().append($('<input>', {name: 'edit_name', value: name}))
      $("td:eq(1)", tr).empty().append($('<input>', {name: 'edit_email', value: email}))
      $("td:eq(2)", tr).prepend("<button class='btn btn-info btn-xs btn-update'>Update</button><button class='btn btn-warning btn-xs btn-cancel'>Cancel</button>")
      $(this).hide()
    })
    .on('click', '.btn-cancel', function(e) {
      const tr = $(this).parents("tr")[0]
      const { name, email } = tr.dataset
    
      $("td:eq(0)", tr).text(name)
      $("td:eq(1)", tr).text(email)
    
      $(".btn-edit", tr).show()
      $(".btn-update, .btn-cancel", tr).remove()
    })
    .on('click', '.btn-update', function(e) {
      const tr = $(this).parents("tr")[0]
      const name = $("input[name='edit_name']", tr).val()
      const email = $("input[name='edit_email']", tr).val()
    
      tr.dataset.name = name
      tr.dataset.email = email
      
      $("td:eq(0)", tr).text(name)
      $("td:eq(1)", tr).text(email)
      $(".btn-edit", tr).show()
      $(".btn-cancel, .btn-update", tr).remove()
    })
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    
    <div class="container">
      <table class="table table-bordered ">
        <thead>
          <th>Name</th>
          <th>Email</th>
          <th width="200px">Action</th>
        </thead>
        <tbody>
          <tr data-name='marzouk najib' data-email='[email protected]'>
            <td>marzouk najib</td>
            <td>[email protected]</td>
            <td><button class='btn btn-info btn-xs btn-edit'>Edit</button></td>
          </tr>
        </tbody>
      </table>
    </div>

    but still this is far away of how i would deal with it, i would separate the logic from js/html

    • HTML should deal with the presentation and javascript should enhance it without knowing things like name or email – think of it like writing a jQuery plugin that could understands the html structor and make it work for any number of columns
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search