finding mutated field value

62 Views Asked by At

How can I get the pprice, pweight, pname values in to an array?

I cannot get input field values from Javascript because the input fields are created dynamically. I tried to use a MutationObserver but I failed. Please help me.

let tbody = document.querySelector('#tbody');
let addBtn = document.querySelector('#addBtn');
let IdString = "tablerow";
let i = 4;

function creatTableEl(id, pname, pweight, pprice) {
  const createTR = document.createElement("tr");
  createTR.setAttribute("id", id);
  tbody.appendChild(createTR);
  const createTD1 = document.createElement("td");
  const createTD2 = document.createElement("td");
  const createTD3 = document.createElement("td");
  const createTD4 = document.createElement("td");
  createTR.append(createTD1, createTD2, createTD3, createTD4);
  const createInputField1 = document.createElement("input");
  createTD1.appendChild(createInputField1);
  createInputField1.setAttribute("type", "text");
  createInputField1.setAttribute('id', pname);
  const createInputField2 = document.createElement("input");
  createTD2.appendChild(createInputField2);
  createInputField2.setAttribute("type", "text");
  createInputField2.setAttribute('id', pweight);
  const createInputField3 = document.createElement("input");
  createTD3.appendChild(createInputField3);
  createInputField3.setAttribute("type", "number");
  createInputField3.setAttribute("id", pprice);
  createTD4.setAttribute("id", "Delete");
  createTD4.innerHTML = "&#10006";
  createTD4.addEventListener("click", DeleteCells);

  function DeleteCells() {
    const deleteCellIDs = createTR.getAttribute("id");
    createTR.remove(deleteCellIDs);
  }
  return createTR;
}

function addTableRowBtn() {
  let id = IdString + i;
  let pname = 'pname' + i;
  let pweight = 'pweight' + i;
  let pprice = 'pprice' + i;
  i++;
  const tableEle = creatTableEl(id, pname, pweight, pprice);
  tbody.insertBefore(tableEle, addBtn);
}

function Table() {
  for (let y = 0; y < 4; y++) {
    let id = IdString + y;
    let pname = 'pname' + y;
    let
      pweight = 'pweight' + y;
    let pprice = 'pprice' + y;
    const
      constTableEle = creatTableEl(id, pname, pweight, pprice);
    tbody.insertBefore(constTableEle, addBtn);
  }
  addBtn.addEventListener("click", addTableRowBtn);
}

Table();
<table class="form-control" name='details'>
  <thead>
    <tr>
      <th class="text-center ">Name</th>
      <th class="text-center">Weight</th<th class="text-center">Price</th>
    </tr>
  </thead>
  <tbody id="tbody">
    <tr class="addBtn " id="addBtn" style="text-align: center;">
      <td colspan="3"><i class="bi bi-plus-circle">+</i></td>
    </tr>
  </tbody>
</table>

1

There are 1 best solutions below

2
On

The fact that the table is dynamically created doesn't preclude you from retrieving the field values. You can achieve this by looping over your tr elements within the tbody with map() to build an array of objects containing the values for each row.

In fact, there's quite a few things you can do to improve your code quality:

  • Use a <template> element in your HTML to avoid having to write a lot of needless JS code creating a repeated HTML structure. Rerieve the template once and inject it as needed.
  • Move the 'Add row' button in to the tfoot so that the tbody only contains your input field rows, which makes working with them much easier as they are separated.
  • Do not use repeated id attribute values in dynamic content. Duplicates which are invalid.
  • Do not create incremental id attribute values while looping through to create HTML content. It's needlessly complex as id attributes are not required in order to target the content you need - as the example below demonstrates.
  • Put all styling in external CSS stylesheets, not inline in your HTML.
  • Use actual clickable elements, eg <a /> or <button />, to trigger events. Don't just attach event handlers to arbitrary containers, such as td.
  • Use a delegated event handler to bnid a single event handler to all element that require it. You don't need to define a new function in every iteration of your loop

With all those adjustments made, try this working example:

const tbody = document.querySelector('table tbody');
const addButtonRow = document.querySelector('#add-button-row');
const rowTemplate = document.querySelector('#row-template').innerHTML;
const addButton = document.querySelector('.add-button');
const outputButton = document.querySelector('#output-button');

const addTableRow = () => tbody.innerHTML += rowTemplate;
const removeTableRow = e => e.target.closest('tr').remove();
const generateTableBody = () => {
  for (let y = 0; y < 4; y++) {
    addTableRow();
  }
}
const generateOutputArray = () => Array.from(tbody.querySelectorAll('tr')).map(tr => ({
  pname: tr.querySelector('.pname').value,
  pweight: tr.querySelector('.pweight').value,
  pprice: tr.querySelector('.pprice').value
}));

addButton.addEventListener('click', addTableRow);
tbody.addEventListener('click', e => {
  if (e.target.classList.contains('delete'))
    removeTableRow(e);
})
outputButton.addEventListener('click', () => {
  console.log(generateOutputArray());
});

generateTableBody();
#add-button-row {
  text-align: center;
}

a {
  text-decoration: none;
}
<table class="form-control" name="details">
  <thead>
    <tr>
      <th class="text-center">Name</th>
      <th class="text-center">Weight</th>
      <th class="text-center">Price</th>
    </tr>
  </thead>
  <tbody></tbody>
  <tfoot>
    <tr id="add-button-row">
      <td colspan="3">
        <a href="#" class="add-button"><i class="bi bi-plus-circle">+</i></a>
      </td>
    </tr>
  </tfoot>
</table>

<template id="row-template">
  <tr>
    <td><input type="text" name="pname" class="pname" /></td>
    <td><input type="text" name="pweight" class="pweight" /></td>
    <td><input type="number" name="pprice" class="pprice" /></td>
    <td><a href="#" class="delete">&#10006</a></td>
  </tr>
</template>

<button id="output-button">Build Array</button>