Rataiczak24 Rataiczak24 - 2 months ago 9
jQuery Question

How to Carry Over Validation onto Newly Added Table Rows

So I have a table with two separate buttons, Edit and Deactivate. I was able to use a bind function on the deactivate and edit in order to get the button to work when I added rows. I also have validation for most of the fields. The validation works perfectly on the original rows, but does not work on any rows that are added by the user. How can I fix this?

HTML/PHP:

<table id="html_master">
<thead>
<tr>
<td>ID</td>
<td>Vendor</td>
<td>Buyer ID</td>
<td>POC Name</td>
<td>POC Email</td>
<td>POC Phone</td>
<td>Edit/Delete</td>
</tr>
</thead>
<tbody>

<?php
foreach ($dbh->query($sql) as $rows){
?>
<tr>
<td class="mr_id" contenteditable="false"><?php echo intval ($rows['MR_ID'])?></td>
<td class="mr_name" contenteditable="false"><?php echo $rows['MR_Name']?></td>
<td class="buyer_id" contenteditable="false"><?php echo $rows['Buyer_ID']?></td>
<td class="poc_n" contenteditable="false"><?php echo $rows['MR_POC_N']?></td>
<td class="poc_e" contenteditable="false"><?php echo $rows['MR_POC_E']?></td>
<td class="poc_p" contenteditable="false"><?php echo $rows['MR_POC_P']?></td>
<td><input type="button" class="edit" name="edit" value="Edit">
<input type="button" class="deactivate" name="deactivate" value="Deactivate"></td>
</tr>
<?php
}
?>
</tbody>
<br>
<input type="button" class="add" value="Add Row" onclick="addRow('html_master')">
</table>

<input type="button" class="add" value="Add Row" onclick="addRow('html_master')">

</body>
</html>


JavaScript:

// ----- Deactivate Row -----

function bindDeactivate() {
$('#html_master').on("click",".deactivate",function() {
var $this = $(this);
var $tr = $this.closest('tr');
var action = $tr.hasClass('deactivated') ? 'activate' : 'deactivate';

if (confirm('Are you sure you want to ' + action + ' this entry?')) {
$tr.toggleClass('deactivated');
$this.val(function(i, t) {
return t == 'Deactivate' ? 'Activate' : 'Deactivate';
});
}
});
}

$(document).ready(function() {
// Bind the deactivate button click to the function
bindDeactivate();
});

$(document).ready(function() {
// Bind the edit button click to the function
bindEdit();
});

// ----- Add Row -----

function addRow(tableID) {

var table = document.getElementById(tableID);

var rowCount = table.rows.length;
var row = table.insertRow(rowCount);

var cell1 = row.insertCell(0);
cell1.innerHTML = rowCount;

var cell2 = row.insertCell(1);
var element2 = document.createElement("input");
element2.type = "text";
element2.name = "txtbox[]";
cell2.appendChild(element2);

var cell3 = row.insertCell(2);
var element3 = document.createElement("input");
element3.type = "text";
element3.name = "txtbox[]";
cell3.appendChild(element3);

var cell4 = row.insertCell(3);
var element4 = document.createElement("input");
element4.type = "text";
element4.name = "txtbox[]";
cell4.appendChild(element4);

var cell5 = row.insertCell(4);
var element5 = document.createElement("input");
element5.type = "text";
element5.name = "txtbox[]";
cell5.appendChild(element5);

var cell6 = row.insertCell(5);
var element6 = document.createElement("input");
element6.type = "text";
element6.name = "txtbox[]";
cell6.appendChild(element6);

var cell7 = row.insertCell(6);
var element7 = document.createElement("input");
var element8 = document.createElement("input");
element7.type = "button";
element8.type = "button";
element7.name="edit";
element8.name="deactivate";

var setClass = document.createAttribute("class");
setClass.value = "edit";
element7.setAttributeNode(setClass);

var setClass1 = document.createAttribute("class");
setClass1.value = "deactivate";
element8.setAttributeNode(setClass1);

element7.attr="class";
element8.attr="class";
element7.value="Edit";
element8.value="Deactivate";
cell7.appendChild(element7);
cell7.appendChild(element8);

// Bind this new deactivate button click to the function
$('#html_master').off("click",'.deactivate');
bindDeactivate();

// Bind this new deactivate button click to the function
$('#html_master').off("click",'.edit');
bindEdit();
}




function bindEdit() {
$('#html_master').on("click",".edit",function() {
var $this = $(this);
var tds = $this.closest('tr').find('td').not('.mr_id').filter(function() {
return $(this).find('.edit').length === 0;
});
if ($this.val() === 'Edit') {
$this.val('Save');
tds.prop('contenteditable', true);
} else {
var isValid = true;
var errors = '';
$('#myDialogBox').empty();
tds.each(function(){
var type = $(this).attr('class');
var value = $(this).text();
switch(type){
case "buyer_id":
if(!$.isNumeric(value)){
isValid = false;
errors += "Please enter a valid Buyer ID\n";
}
break;
case "poc_n":
if(value == value.match(/^[a-zA-Z\s]+$/)){
break;
}
else {
isValid = false;
errors += "Please enter a valid Name\n";
}
break;
case "poc_e":
if(value == value.match(/^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/)){
break;
}
else {
isValid = false;
errors += "Please enter a valid Email\n";
}
break;
case "poc_p":
if(value == value.match('^[0-9 ()+/-]{10,}$')){
break;
}
else {
isValid = false;
errors += "Please enter a valid Phone Number\n";
}
break;
}
})
if(isValid){
$this.val('Edit'); // Modifed
tds.prop('contenteditable', false);
}else{
alert(errors);
}
}
});
}

Answer

For newly created dom elements your approach to delegation is complicated. I suggest you to simplify it:

$(document).on("click", "#html_master .deactivate", function () {
$(document).on("click", "#html_master .edit", function () {

This will avoid confusion and reduce line numbers: you do not need to bind -- unbind -- bind event.

The problem you are experiencing with the validation is related on how you ceate the new elements. They need the class you are looking for in the validation. So in your function addRow(tableID) { for each new element you need to add the class like:

element2.className = 'mr_name';

So the snippet is:

// ----- Deactivate/Activate Row -----

$(document).on("click", "#html_master .deactivate", function () {
  var $this = $(this);
  var $tr = $this.closest('tr');
  var action = $tr.hasClass('deactivated') ? 'activate' : 'deactivate';

  // ------ Confirmation box in order to deactivate/activate row -----
  if (confirm('Are you sure you want to ' + action + ' this entry?')) {
    $tr.toggleClass('deactivated');
    $this.val(function (i, t) {
      return t == 'Deactivate' ? 'Activate' : 'Deactivate';
    });
  }
});

// ----- Edit Row -----

$(document).on("click", "#html_master .edit", function () {
  var $this = $(this);
  var tds = $this.closest('tr').find('td').not('.mr_id').filter(function () {
    return $(this).find('.edit').length === 0;
  });
  if ($this.val() === 'Edit') {
    $this.val('Save');
    tds.prop('contenteditable', true);
  } else {
    var isValid = true;
    var errors = '';
    $('#myDialogBox').empty();
    // changed from here.......
    var elements = tds;
    if (tds.find('input').length > 0) {
      elements = tds.find('input');
    }
    elements.each(function (index, element) {
      var type = $(this).attr('class');
      var value = (element.tagName == 'INPUT') ? $(this).val() : $(this).text();
      // changed from here....... to here
      // ----- Switch statement that provides validation -----
      switch (type) {
        case "buyer_id":
          if (!$.isNumeric(value)) {
            isValid = false;
            errors += "Please enter a valid Buyer ID\n";
          }
          break;
        case "poc_n":
          if (value == value.match(/^[a-zA-Z\s]+$/)) {
            break;
          }
          else {
            isValid = false;
            errors += "Please enter a valid Name\n";
          }
          break;
        case "poc_e":
          if (value == value.match(/^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/)) {
            break;
          }
          else {
            isValid = false;
            errors += "Please enter a valid Email\n";
          }
          break;
        case "poc_p":
          if (value == value.match('^[0-9 ()+/-]{10,}$')) {
            break;
          }
          else {
            isValid = false;
            errors += "Please enter a valid Phone Number\n";
          }
          break;
      }
    })
    if (isValid) {
      $this.val('Edit');
      tds.prop('contenteditable', false);
    } else {
      alert(errors);
    }
  }
});


// ----- Add Row -----

function addRow(tableID) {

  var table = document.getElementById(tableID);

  var rowCount = table.rows.length;
  var row = table.insertRow(rowCount);

  var cell1 = row.insertCell(0);
  cell1.innerHTML = rowCount;
  cell1.className = 'mr_id';

  var cell2 = row.insertCell(1);
  var element2 = document.createElement("input");
  element2.type = "text";
  element2.name = "txtbox[]";
  element2.className = 'mr_name';
  cell2.appendChild(element2);

  var cell3 = row.insertCell(2);
  var element3 = document.createElement("input");
  element3.type = "text";
  element3.name = "txtbox[]";
  element3.className = 'buyer_id';
  cell3.appendChild(element3);

  var cell4 = row.insertCell(3);
  var element4 = document.createElement("input");
  element4.type = "text";
  element4.name = "txtbox[]";
  element4.className = 'poc_n';
  cell4.appendChild(element4);

  var cell5 = row.insertCell(4);
  var element5 = document.createElement("input");
  element5.type = "text";
  element5.name = "txtbox[]";
  element5.className = 'poc_e';
  cell5.appendChild(element5);

  var cell6 = row.insertCell(5);
  var element6 = document.createElement("input");
  element6.type = "text";
  element6.name = "txtbox[]";
  element6.className = 'poc_p';
  cell6.appendChild(element6);

  var cell7 = row.insertCell(6);
  var element7 = document.createElement("input");
  var element8 = document.createElement("input");
  element7.type = "button";
  element8.type = "button";
  element7.name = "edit";
  element8.name = "deactivate";

  var setClass = document.createAttribute("class");
  setClass.value = "edit";
  element7.setAttributeNode(setClass);

  var setClass1 = document.createAttribute("class");
  setClass1.value = "deactivate";
  element8.setAttributeNode(setClass1);

  element7.attr = "class";
  element8.attr = "class";
  element7.value = "Save";
  element8.value = "Deactivate";
  cell7.appendChild(element7);
  cell7.appendChild(element8);
}
table {
  border-collapse: collapse;
}

td {
  border: 1.5px solid black;
  padding: 3px;
}

thead {
  font-weight: bold;
}

.deactivated {
  opacity: 0.5;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>


<table id="html_master">
    <thead>
    <tr>
        <td>ID</td>
        <td>Vendor</td>
        <td>Buyer ID</td>
        <td>POC Name</td>
        <td>POC Email</td>
        <td>POC Phone</td>
        <td>Edit/Delete</td>
    </tr>
    </thead>
    <tbody>

    <?php
    foreach ($dbh->query($sql) as $rows){
    ?>
    <tr>
        <td class="mr_id" contenteditable="false"><?php echo intval ($rows['MR_ID'])?></td>
        <td class="mr_name" contenteditable="false"><?php echo $rows['MR_Name']?></td>
        <td class="buyer_id" contenteditable="false"><?php echo $rows['Buyer_ID']?></td>
        <td class="poc_n" contenteditable="false"><?php echo $rows['MR_POC_N']?></td>
        <td class="poc_e" contenteditable="false"><?php echo $rows['MR_POC_E']?></td>
        <td class="poc_p" contenteditable="false"><?php echo $rows['MR_POC_P']?></td>
        <td><input type="button" class="edit" name="edit" value="Edit">
            <input type="button" class="deactivate" name="deactivate" value="Deactivate"></td>
    </tr>
    <?php
  }
 ?>
    </tbody>
    <br>
    <input type="button" class="add" value="Add Row" onclick="addRow('html_master')">
</table>

<input type="button" class="add" value="Add Row" onclick="addRow('html_master')">

Comments