JavaScript new Table row Class not applying

58 Views Asked by At

In my web application, There is a table and Add button.

Whenever the user clicks on the Add button, from javascript, I load the new row to the table.

In the row, there is a element and for that class, I added the Select2 js-dropdown class when adding to the new row.

But when it was added, Js-dropdown class was not applied.

How can I add it?

this is the current code.

<table class="table table-striped" id="submissionTable">
  <thead>
    <tr>
      <th>#</th>
      <th>ITEM</th>
      <th>QTY</th>
      <th>MEASURE BY</th>
      <th>UNIT PRICE</th>
      <th>LINE TOTAL</th>
    </tr>
  </thead>
  <tbody class="table-border-bottom-0">
    <tr id="tablerow0"></tr>
  </tbody>
</table>

This is the javascript code.

  $(function () {

    $("#add").click(function () {
      var newRow = $(
        '<tr id="tablerow' +
        counter +
        '"> ' +
        "<td>" +
        '<label id="CountItems"><strong>' +
        counter +
        "</strong></label>" +
        "</td>" +
        '<td width="40%">' +
        '<select onchange="sendInfo(this)" class="form-select js-dropdown" data-id= ' + counter + ' name="Item_Id[' +
        counter +
        ']" id="ItemId"' + counter + 'required="required" ' +
        "</select>" +
        "</td>" +
        '<td width="10%">' +
        '<input type="text" class="form-control" name="Qty[' +
        counter +
        ']" value="1" id="Qty[' + counter + ']" onchange="calQtyBase(this)" data-QtyId= ' + counter + ' required="required" />' +
        "</td>" +
        '<td width="10%">' +
        '<input type="text" class="form-control" name="MeasureBy[' +
        counter +
        ']" value="" id="MeasureBy[' + counter + ']" readonly />' +
        "</td>" +
        '<td width="20%">' +
        '<input type="text" class="form-control" name="Unit_Price[' +
        counter +
        ']" value="0.00" id="UnitPrice[' + counter + ']"  onchange="priceBase(this)" data-PriceId= ' + counter + '  required="required" />' +
        "</td>" +
        '<td width="20%">' +
        '<input type="text" class="form-control" name="Line_Total[' +
        counter +
        ']" value="0.00" id="LineTotal[' + counter + ']"    required="required" />' +
        "</td>" +
        "<td>" +
        '<button type="button" class="btn btn-danger" onclick="removeTr(' +
        counter +
        ');">x</button>' +
        "</td>" +
        "</tr>"
      );

      var selectElement = newRow.find("select"); // Find the <select> element in the new row

      // Populate the <select> element with options
      dropdownOptions.forEach(function (option) {

        var optionElement = $("<option>").val(option.Value).text(option.Text);

        selectElement.append(optionElement);

      });

      newRow.appendTo("#submissionTable");
      counter++;
      return false;
    });

  });
2

There are 2 best solutions below

2
Tom On

If you want to select2 jquery plugin work on new select element added to DOM, you need to initialize it on this select.

$(()=>{
  
  let $target = $("#target");
  let $btn = $("#add");
  
  $btn.on('click', function(){
    let $select = $("<select><option>first</option><option>second</option></select>");
    $target.append($select);
    $select.select2(); // this must be called after append
  });

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>

<div id="target"></div>
<button id="add">Add</button>

edit

You have a syntax error, so it may not work for you. replace ']" id="ItemId"' + counter + 'required="required" ' + On ']" id="ItemId' + counter + '" required="required" ' + I fixed this error see below.

$(function () {
  let counter = 1;
  let dropdownOptions = [{Value:'0', Text: 'first'}, {Value:'1', Text: 'second'}];
    $("#add").click(function () {
      var newRow = $(
        '<tr id="tablerow' +
        counter +
        '"> ' +
        "<td>" +
        '<label id="CountItems"><strong>' +
        counter +
        "</strong></label>" +
        "</td>" +
        '<td width="40%">' +
        '<select onchange="sendInfo(this)" class="form-select js-dropdown" data-id= ' + counter + ' name="Item_Id[' +
        counter +
        ']" id="ItemId' + counter + '" required="required" ' +
        "</select>" +
        "</td>" +
        '<td width="10%">' +
        '<input type="text" class="form-control" name="Qty[' +
        counter +
        ']" value="1" id="Qty[' + counter + ']" onchange="calQtyBase(this)" data-QtyId= ' + counter + ' required="required" />' +
        "</td>" +
        '<td width="10%">' +
        '<input type="text" class="form-control" name="MeasureBy[' +
        counter +
        ']" value="" id="MeasureBy[' + counter + ']" readonly />' +
        "</td>" +
        '<td width="20%">' +
        '<input type="text" class="form-control" name="Unit_Price[' +
        counter +
        ']" value="0.00" id="UnitPrice[' + counter + ']"  onchange="priceBase(this)" data-PriceId= ' + counter + '  required="required" />' +
        "</td>" +
        '<td width="20%">' +
        '<input type="text" class="form-control" name="Line_Total[' +
        counter +
        ']" value="0.00" id="LineTotal[' + counter + ']"    required="required" />' +
        "</td>" +
        "<td>" +
        '<button type="button" class="btn btn-danger" onclick="removeTr(' +
        counter +
        ');">x</button>' +
        "</td>" +
        "</tr>"
      );

      var selectElement = newRow.find("select"); // Find the <select> element in the new row

      // Populate the <select> element with options
      dropdownOptions.forEach(function (option) {

        var optionElement = $("<option>").val(option.Value).text(option.Text);

        selectElement.append(optionElement);
      });

      
      newRow.appendTo("#submissionTable");
      selectElement.select2();
      
      
      counter++;
      return false;
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>

<table class="table table-striped" id="submissionTable">
  <thead>
    <tr>
      <th>#</th>
      <th>ITEM</th>
      <th>QTY</th>
      <th>MEASURE BY</th>
      <th>UNIT PRICE</th>
      <th>LINE TOTAL</th>
    </tr>
  </thead>
  <tbody class="table-border-bottom-0">
    <tr id="tablerow0"></tr>
  </tbody>
</table>

<button id="add">click me</button>

0
Mark Schultheiss On

A little different approach; sorry this is just a really really fast post here:

  • use an object to hold the constants and not global.
  • No need for global counter; seems overly complex to even NEED that used (use classes?)
  • use a template and cloned that to make markup simpler to edit/understand
  • some simple wire-up of event handlers that do little here.

$(function() {
  function handleTableRowRemoval(event) {
    const row = event.target.closest('tr.row-thing');
    const rowCount = row.dataset.Count;
    $(row).remove();
    //whatever else needs done: removeTr(rowCount);
  }

  function handlePriceBaseEvent(event) {
    //do whatever calQtyBase(this);
  }

  function handleSelectChangeEvent(event) {
    // whatever sendInfo(this);
  }
  $("#add").on('click', function(event) {
    const newThings = {
      templateselector: "#new-row",
      rowIdBase: "tablerow-",
      newRowId: "",
      tableSelector: '#submissionTable tbody',
      selectSelector: '.form-select.js-dropdown.item-id',
      count: 0,
      dropdownOptions: [{
        Value: '0',
        Text: 'first'
      }, {
        Value: '1',
        Text: 'second'
      }]
    };

    const table = document.querySelector(newThings.tableSelector);
    const template = document.querySelector(newThings.templateselector);
    const cloneRow = template.content.firstElementChild.cloneNode(true);
    newThings.currentCount = $(table).data("currentcount") * 1;

    // id might not be needed?
    newThings.newRowId = newThings.rowIdBase + newThings.count;
    cloneRow.id = newThings.newRowId;
    // what we work with 
    const selectControl = cloneRow.querySelector(newThings.selectSelector);
    const qtyBase = cloneRow.querySelector('.form-control.qty-base');
    const unitPrice = cloneRow.querySelector('.form-control.unit-price');
    const measureBy = cloneRow.querySelector('.form-control.measure-by');
    const lineTotal = cloneRow.querySelector('.form-control.line-total');

    //put the event hanldlers on
    selectControl.addEventListener("change", handleSelectChangeEvent);
    unitPrice.addEventListener("click", handlePriceBaseEvent);
    cloneRow.querySelector('.remove-row').addEventListener("click", handleTableRowRemoval);

    // add count where needed
    cloneRow.dataset.Count = newThings.count;
    cloneRow.id = `tablerow${newThings.count}`;

    selectControl.name = `Item_Id[${newThings.count}`;
    selectControl.textContent = newThings.count;
    selectControl.dataset.Id = newThings.count;

    measureBy.name = `MeasureBy[${newThings.count}`;
    measureBy.id = `MeasureBy[${newThings.count}`;

    qtyBase.name = `Qty[${newThings.count}`;
    qtyBase.id = `Qty[${newThings.count}`;
    qtyBase.dataset.QtyId = newThings.count;

    unitPrice.name = `Unit_Price[${newThings.count}`;
    unitPrice.id = `Unit_Price[${newThings.count}`;
    unitPrice.dataset.PriceId = newThings.count;

    lineTotal.name = `Line_Total[${newThings.count}`;
    lineTotal.id = `Line_Total[${newThings.count}`;
    lineTotal.dataset.PriceId = newThings.count;

    // Populate the <select> element with options
    newThings.dropdownOptions.forEach(function(option) {
      const optionElement = $("<option>").val(option.Value).text(option.Text);
      $(selectControl).append(optionElement);
    });

    // append new row to table after all that 
    table.appendChild(cloneRow);
    //only seems to work after append
    $(table).find(newThings.selectSelector).last().select2();
    return false;
  });
});
/* if for example using bootstrap can perhaps use classes from there instead */

.forty-percent {
  width: 40%;
}

.ten-percent {
  width: 10%;
}

.twenty-percent {
  width: 10%;
}

.count-items .label-count-value {
  font-weight: 600;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" integrity="sha512-nMNlpuaDPrqlEls3IX/Q56H36qvBASwb3ipuo3MxeWbsQB1881ox0cRv7UPTgBlriqoynt35KjEwgGUeUXIPnw==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js" integrity="sha512-2ImtlRlf2VVmiGZsjm9bEyhjGW4dU7B6TNwh/hx/iSByxNENtj3WVE6o/9Lj4TJeVXPi4bnOIMXFIJJAeufa0A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<button id="add" type="button" class="add-new-row">Add new row</button>
<table class="table table-striped" id="submissionTable" data-currentcount="0">
  <thead>
    <tr>
      <th>#</th>
      <th>ITEM</th>
      <th>QTY</th>
      <th>MEASURE BY</th>
      <th>UNIT PRICE</th>
      <th>LINE TOTAL</th>
    </tr>
  </thead>
  <tbody class="table-border-bottom-0 ">
    <tr id="tablerow0"></tr>
  </tbody>
</table>
<template id="new-row">
<tr id="tablerow" class="row-thing"> 
  <td><label class="count-items"><strong class="label-count-value"></strong></label></td>
  <td class="forty-percent"><select class="form-select js-dropdown item-id" required="required" ></select></td>
  <td class="ten-percent"><input type="text" class="form-control qty-base" value="1" data-qty-Id='' required="required" /></td>
  <td class="ten-percent"><input type="text" class="form-control measure-by" value="" readonly /></td>
  <td class="twenty-percent"><input type="text" class="form-control unit-price"  value="0.00" data-PriceId='xx' required="required" /></td>
  <td class="twenty-percent"><input type="text" class="form-control line-total"  value="0.00" required="required" /></td>
  <td><button type="button" class="btn btn-danger remove-row">x</button></td>
</tr>
</template>