skip to Main Content

I have a table in my html file.

<table class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th>timestamp</th>
      <th>cid1</th>
      <th>cid2</th>
      <th>cid3</th>
      <th>cid4</th>
      <th>cid5</th>
      <th>cid6</th>
      <th>cid7</th>
      <th>cid8</th>
      <th>cid9</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>2023-04-08 15:39:21</td>
      <td>125</td>
      <td>4342&</td>
      <td>73645</td>
      <td>246</td>
      <td>4624</td>
      <td>1137504</td>
      <td>62467</td>
      <td>16596</td>
      <td>302207.827877119</td>
    </tr>
    <tr>
      <td>2023-04-08 15:39:21</td>
      <td>62462</td>
      <td>462436</td>
      <td>462436</td>
      <td>2462436</td>
      <td>2</td>
      <td>4924872</td>
      <td>46246</td>
      <td>16619</td>
      <td>1769805.989015266</td>
    </tr>
  </tbody>
</table>

This file created by my python script and I want to add inside js script for recount table without call my backend. Inside data follow the formulas: cid6 = cid4*cid5 and cid9=cid6/cid7*cid8

I want to paste in my html input form for new_cid4 value which must to replace each cid4 values in the table only for rows where ‘cid4’ < ‘new_cid4’. As result I want to recount values of columns cid6, cid9. Аnd very good if rows where cid4 > new_cid4 will be hided.

I’m pythonist and can’t to make this js script myself. May be JS masters can help me?

3

Answers


  1. Basically, you need to add an event listener to the element in question.

    First, query elements from the document using document.querySelector() (assuming you have one <input> and one <button>; I made a snippet below for your reference):

    <input type="number">
    <button>Submit</button>
    
    const input = document.querySelector('input');
    const button = document.querySelector('button');
    

    Then, add an event listener:

    button.addEventListener('click', () => {
      // Retrieve the value of <input>. This value is a string.
      const new_cid4 = input.value;
    
      // Get all rows in an array-like.
      const rows = document.querySelectorAll('tbody tr');
    
      // Iterate over each row
      for (const row of rows) {
        // Shortcut lambdas
        const cell = index => row.children[index];
        const cellValue = index => cell(index).textContent;
    
        const cid4 = cellValue(4);
    
        // Convert to number explicitly since we're comparing.
        if (Number(cid4) >= Number(new_cid4)) {
          // Add an inline 'display: none' for the row.
          row.style.display = 'none';
          continue;
        }
    
        // Remove inline 'display', if any.
        row.style.removeProperty('display');
    
        // Calculate new cell values.
        // Note that JS automatically convert strings to numbers when multiplying / dividing.
        // (i.e. no need to use Number() explicitly)
        cell(4).textContent = new_cid4;
        cell(6).textContent = new_cid4 * cellValue(5);
        cell(9).textContent = cellValue(6) / cellValue(7) * cellValue(8);
      }
    });
    

    Try it:

    // Demo only
    addRandomData();
    
    const input = document.querySelector('input');
    const button = document.querySelector('button');
    
    button.addEventListener('click', () => {
      const new_cid4 = input.value;
    
      const rows = document.querySelectorAll('tbody tr');
    
      for (const row of rows) {
        const cell = index => row.children[index];
        const cellValue = index => cell(index).textContent;
    
        const cid4 = cellValue(4);
    
        // Unary '+' is a shortcut for Number().
        if (+cid4 >= +new_cid4) {
          row.style.display = 'none';
          continue;
        }
        
        row.style.removeProperty('display');
    
        cell(4).textContent = new_cid4;
        cell(6).textContent = new_cid4 * cellValue(5);
        cell(9).textContent = (
          cellValue(6) / cellValue(7) * cellValue(8)
        ).toFixed(2); // Decimal places
    
        // Demo only
        blink(row);
      }
    });
    
    
    /* Demo only */
    
    function addRandomData() {
      const tbody = document.querySelector('tbody');
    
      const max = 2 + Math.random() * 10 | 0;
    
      for (let i = 0; i < max; i++) {
        const row = document.createElement('tr');
    
        row.appendChild(createCell('2023-05-08 15:39:21'));
    
        for (let j = 0; j < 9; j++) {
          row.appendChild(
            createCell(Math.random() * 1e3 | 0)
          );
        }
    
        const calculator = cellCalculatorFromRow(row)
        calculator(6, row => row[4] * row[5]);
        calculator(9, row => row[6] / row[7] * row[8]);
    
        tbody.appendChild(row);
      }
    }
    
    function createCell(text = '') {
      const cell = document.createElement('td');
      cell.textContent = text;
      return cell;
    }
    
    function cellCalculatorFromRow(row) {
      const cellValues = new Proxy(row, {
        get(target, property) {
          return +target.children[property].textContent;
        }
      });
      return function(index, callback) {
        row.children[index].textContent = +callback(cellValues).toFixed(2);
      }
    }
    
    function blink(row) {
      row.animate([
        { background: '#ff0' },
        { background: '#fff' }
      ], 700);
    }
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
    }
    
    #form {
      margin: 1em 0;
    }
    <table class="dataframe">
      <thead>
        <tr style="text-align: right">
          <th>timestamp</th>
          <th>cid1</th>
          <th>cid2</th>
          <th>cid3</th>
          <th>cid4</th>
          <th>cid5</th>
          <th>cid6</th>
          <th>cid7</th>
          <th>cid8</th>
          <th>cid9</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>2023-04-08 15:39:21</td>
          <td>125</td>
          <td>4342</td>
          <td>73645</td>
          <td>246</td>
          <td>4624</td>
          <td>624</td>
          <td>62467</td>
          <td>16596</td>
          <td>0.65</td>
        </tr>
        <tr>
          <td>2023-04-08 15:39:21</td>
          <td>62462</td>
          <td>462436</td>
          <td>462436</td>
          <td>2462436</td>
          <td>2436246</td>
          <td>462436</td>
          <td>46246</td>
          <td>16619</td>
          <td>0.51</td>
        </tr>
      </tbody>
    </table>
    
    <div id="form">
      <input type="number">
      <button>Submit</button>
    </div>
    Login or Signup to reply.
  2. Version with html input. It recalculate values and hides rows where this condition is not met cid4 <= new_cid4. It also gets all the table values and create the array of objects out of them.

    const updateRow = (new_cid4, rowData, reset = false) => {
        const { cid1, cid2, cid3, cid5, cid7, cid8 } = rowData;
        let { cid4, cid6, cid9 } = rowData;
        if (!reset) cid4 = cid4 <= new_cid4 ? new_cid4 : cid4;
        cid6 = cid4 * cid5;
        cid9 = (cid6 / cid7) * cid8;
        return { cid1, cid2, cid3, cid4, cid5, cid6, cid7, cid8, cid9,};
    };
    
    const updateRowDOM = (row, rowData, hideRow = false) => {
        row.querySelector('td:nth-child(5)').textContent = rowData.cid4;
        row.querySelector('td:nth-child(7)').textContent = rowData.cid6;
        row.querySelector('td:nth-child(10)').textContent = rowData.cid9;
        row.classList.toggle('hidden', hideRow);
    };
    
    const cid4Input = document.getElementById('cid4Input');
    const updateButton = document.getElementById('updateButton');
    const rows = document.querySelectorAll('.dataframe tbody tr');
    
    
    let new_cid4 = 0;
    let data = [...rows].map((row) => {
        const timestamp = row.querySelector('td:first-child').textContent;
        const rowData = [...row.querySelectorAll('td:nth-child(n+1)')].reduce(
            (acc, td, index) => ({...acc,[`cid${index}`]: parseFloat(td.textContent.replace(',', '.')) }), {}
        );
        const updatedRowData = updateRow(new_cid4, rowData);
    
        return {
            timestamp,
            ...updatedRowData,
        };
    });
    
    let defaultData = [...data];
    
    const handleUpdate = (new_cid4, data, reset = false) => {
        return data.map((rowData, index) => {
            const row = rows[index];
            const hideRow = !reset ? rowData.cid4 >= new_cid4 : false;
    
            const updatedRowData = updateRow(new_cid4, rowData, reset);
            updateRowDOM(row, updatedRowData, hideRow);
    
            return {timestamp: rowData.timestamp,  ...updatedRowData,
            };
        });
    };
    
    updateButton.addEventListener('click', () => {
        const new_cid4 = Number(cid4Input.value);
        data = new_cid4 ?
            handleUpdate(new_cid4, data, false) :
            handleUpdate(0, defaultData, true);
    });
    .dataframe {
      border-collapse: collapse;
      width: 100%;
      border: 1px solid #dee2e6;
     }
      th,td {
       padding: 0.5rem;
       text-align: left;
       border: 1px solid #dee2e6;
     }
      
       th {
        font-weight: bold;
      }
      .controls{
        padding: 0 0 20px 0;
      }
      .hidden{
         display:none;
     }
    <div id="wrap">
    <div class="controls">
     <input type="number" id="cid4Input">
      <button id="updateButton">Update cid4</button>
    </div>
       <table class="dataframe">
     <thead>
       <tr style="text-align: right;">
         <th>timestamp</th>
         <th>cid1</th>
         <th>cid2</th>
         <th>cid3</th>
         <th>cid4</th>
         <th>cid5</th>
         <th>cid6</th>
         <th>cid7</th>
         <th>cid8</th>
         <th>cid9</th>
       </tr>
     </thead>
     <tbody>
       <tr>
         <td>2023-04-08 15:39:21</td>
         <td>125</td>
         <td>4342&</td>
         <td>73645</td>
         <td>246</td>
         <td>4624</td>
         <td>1137504</td>
         <td>62467</td>
         <td>16596</td>
         <td>302207,827877119</td>
       </tr>
       <tr>
         <td>2023-04-08 15:39:21</td>
         <td>62462</td>
         <td>462436</td>
         <td>462436</td>
         <td>2462436</td>
         <td>2</td>
         <td>4924872</td>
         <td>46246</td>
         <td>16619</td>
         <td>1769805,989015266</td>
       </tr>
     </tbody>
       </table>
       
       </div>
    Login or Signup to reply.
  3. First, you need to determine th cell indices, and then make a calculation tbody tr based on them.

    new_cid4.oninput = function() {
      const value = this.value ?? Number(this.value);
      const tables = document.querySelectorAll('.dataframe');
      
      tables.forEach(table => {
        /* get cels indexes */
        const cels = [...table.querySelectorAll('th')].reduce((prev, current, index) => {
         prev[current.textContent] = index;
         return prev;
        }, {})
        
        /* cid4 */
        if (cels.cid4) {
         table.querySelectorAll(`td:nth-child(${cels.cid4 + 1})`).forEach(el => {
          if (!el.dataset.initialValue) {
            el.dataset.initialValue = Number(el.textContent);
          }
          const tr = el.closest('tr');
          tr.style.display = 'table-row';
          /* restore */
          if (value === '') {
            el.textContent = el.dataset.initialValue;
            return;
          }
          const val = Number(el.textContent);
          if (val <= value) {
            el.textContent = value;
          } else {
            tr.style.display = 'none';
          }
         })
        }
        
        table.querySelectorAll('tbody tr').forEach(tr => {
         /* cid6 = cid4*cid5 */
         if (cels.cid6, cels.cid4, cels.cid5) {
          const cid4 = getCell(cels.cid4);
          const cid5 = getCell(cels.cid5);
          const cid6 = getCell(cels.cid6);
          cid6.textContent = Number(cid4.textContent) * Number(cid5.textContent);
         }
         /* cid9=cid6/cid7*cid8 */
         if (cels.cid9, cels.cid6, cels.cid7, cels.cid8) {
          const cid9 = getCell(cels.cid9);
          const cid6 = getCell(cels.cid6);
          const cid7 = getCell(cels.cid7);
          const cid8 = getCell(cels.cid8);
          cid9.textContent = Number(cid6.textContent) / Number(cid7.textContent) * Number(cid8.textContent);
         }
         function getCell(index) {
          return tr.querySelector(`td:nth-child(${index + 1})`);
         }
        })
      })
    }
    .dataframe {
      border-collapse: collapse;
      border-spacing: 0;
      width: 100%;
    }
    
    .dataframe td {
      padding: 5px;
      border: solid 1px #ccc;
    }
    <table class="dataframe">
      <thead>
       <tr style="text-align: right;">
        <th>timestamp</th>
        <th>cid1</th>
        <th>cid2</th>
        <th>cid3</th>
        <th>cid4</th>
        <th>cid5</th>
        <th>cid6</th>
        <th>cid7</th>
        <th>cid8</th>
        <th>cid9</th>
       </tr>
      </thead>
      <tbody>
       <tr>
        <td>2023-04-08 15:39:21</td>
        <td>125</td>
        <td>4342</td>
        <td>73645</td>
        <td>246</td>
        <td>4624</td>
        <td>1137504</td>
        <td>62467</td>
        <td>16596</td>
        <td>302207.827877119</td>
       </tr>
       <tr>
        <td>2023-04-08 15:39:21</td>
        <td>62462</td>
        <td>462436</td>
        <td>462436</td>
        <td>2462436</td>
        <td>2</td>
        <td>4924872</td>
        <td>46246</td>
        <td>16619</td>
        <td>1769805.989015266</td>
       </tr>
      </tbody>
    </table>
    <br><br>
    <input type="number" id="new_cid4" placeholder="new_cid4">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search