Home > Back-end >  How to use jQuery to set a value in all following rows of a table?
How to use jQuery to set a value in all following rows of a table?

Time:10-08

I have a table having 15 rows of text boxes with ids text1, text2 ... text15 etc.

If I write something suppose in the 5th text box I want the same text to be written in all subsequent boxes i.e the 6th, 7th, 8th ... 15th.

The following code has done the job but only for the first textbox. I want it for any textboxes.

How can I modify the code to achieve the goal?

$(document).ready(function() {
  i = 1;
  var iki = i   1;
  
  $('#text'   i).keyup(function() {
    for (var k = iki; k <= 15; k  ) {
      $('#text'   k).val($(this).val());
    }
  });
});

CodePudding user response:

To do what you require place a common class on all your input elements. This will make them much easier to select. I'd also suggest removing the incremental id attributes as they are an anti-pattern which makes code more complex than it needs to be.

Once you've attached the event handler you can use the Event passed to the handler to retrieve the element which caused the event. From there you can use DOM traversal to find the nearest tr element, and all following tr, before updating the input elements within them.

jQuery($ => {
  $('.foo').on('input', e => {
    $(e.target).closest('tr').nextAll('tr').find('.foo').val(e.target.value);
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<table>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
  <tr><td><input type="text"  /></td></tr>
</table>

CodePudding user response:

While you've already accepted an answer, I thought I'd offer a non-jQuery alternative, which should function perfectly well in your own use-case as well.

The examples are below, with explanatory comments in the JavaScript:

// Utility functions and helpers:
const D = document,
  // an alias for both Document.querySelector() and Element.querySelector()
  // depending on what (if any) context is passed in to the function:
  get = (selector, context = D) => context.querySelector(selector),
  // an alias for Document.querySelectorAll(), and Element.querySelectorAll(),
  // again dependant upon the passed-in context (if any), which returns
  // an Array in order to allow use of Array methods:
  getAll = (selector, context = D) => [...context.querySelectorAll(selector)],
  // a function to handle the input events on the <input> elements, the function
  // takes a reference to the Event Object (from the later call to
  // EventTarget.addEventListener():
  onUpdate = (evt) => {
    // from the Event Object we retrieve the element to which
    // the function was bound:
    let current = evt.currentTarget,
      // from that element we retreive the value and parentNode
      // properties using destructuring assignment:
      {
        value,
        parentNode
      } = current,
      // and from the current element we then retrieve the closest '<tr>'
      // element, and from there we use another destructuring assignment
      // to retrieve the rowIndex property-value:
      {
        rowIndex
      } = current.closest('tr');

    // we then use the getAll() helper function to retrieve all <tr> elements
    // in the document:
    getAll('tr')
      // and pass that Array of Nodes to Array.prototype.filter():
      .filter(
        // using its anonymous Arrow function (having passed in a reference
        // to the current Node ('el') of the Array of Nodes, and the
        // index ('i') of the current Node in the Array.
        // if the current index ('i') is greater than the rowIndex
        // we found earlier we retain the element in the Array:
        (el, i) => i > rowIndex
      // we then pass that filtered Array to Array.prototype.map():
      ).map(
        // again using the anonymous Arrow function, to pass in the
        // <input> element found within this <tr>:
        (row) => get('input', row)
      // passing the Array formed by Array.prototype.map() to
      // Array.prototype.forEach():
      ).forEach(
        // and here we pass in a reference to the current <input>
        // element, and update its value property to be equal to
        // the value we found earlier:
        (input) => input.value = value
      );
  };

// retrieving all <input> elements that are the children of a <td> element, and iterating
// over that Array with Array.prototype.forEach():
getAll('td>input').forEach(
  // 'el' is a reference to the current <input> element of the Array of <input> elements,
  // and here in the Arrow function we bind the onUpdate() function as the event-handler
  // for the 'input' event fired on those <input> elements:
    (el) => el.addEventListener('input', onUpdate)
);
*, ::before,::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

table {
  border-collapse: collapse;
  inline-size: clamp(30rem, 50vw, 900px);
  margin-block: 1em;
  margin-inline: auto;
  table-layout: fixed;
}

:is(th, td):first-child {
  width: 12ex;
}

td {
  border-block: 1px solid currentColor;
  padding-block: 0.5em;
  padding-inline: 1em;
}

td:first-child {
  border-inline-start: 1px solid currentColor;
}

td:last-child {
  border-inline-end: 1px solid currentColor;
}

tr:focus-within td {
  color: rebeccapurple;
}

input {
  color: inherit;
  inline-size: 100%;
  object-fit: cover;
}
<table>
  <thead>
    <tr>
      <th>Number</th>
      <th>Name</th>
      <th>Other</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>2</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>3</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>4</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>5</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>6</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>7</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>8</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>9</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>10</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>11</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>12</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>13</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>14</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
    <tr>
      <td>15</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
    </tr>
  </tbody>
</table>

JS Fiddle demo.

There is the potential that you may need to work with specific <input> elements based on the column that they're in; if that's the case then the following should achieve your aims:

const D = document,
  get = (selector, context = D) => context.querySelector(selector),
  getAll = (selector, context = D) => [...context.querySelectorAll(selector)],
  onUpdate = (evt) => {
    let current = evt.currentTarget,
      {
        value,
        parentNode
      } = current,
      {
        cellIndex
      } = current.closest('td'),
      {
        rowIndex
      } = current.closest('tr');

    // here we retrieve all <tr> elements within the <tbody>:
    getAll('tbody tr')
      // we use Array.prototype.slice() to work only on
      // those <tr> elements which are later in the DOM
      // than the <tr> in which the current <input> appears:
      .slice(rowIndex)
      // we then use Array.prototype.map() to create a new
      // Array comprised of appropriate <input> elements:
      .map(
        // we pass in a reference to the current <tr> of the
        // Array of <tr> elements; and from there we retrieve
        // the <input> elements which are in the same column
        // as the current <input> element; because we're
        // switching from zero-based JavaScript indexing to
        // CSS one-based counting we add 1 to the cellIndex
        // we retrieve earlier, and we pass in the context
        // of the current <tr> element to the get() function:
        (row) => get(`td:nth-child( ${cellIndex   1} ) > input`, row)
        // we then iterate over that Array of <input> elements
        // using Array.prototype.forEach():
      ).forEach(
        // here, again, we simply update the current <input> ('el')
        // to set its value property to be equal to the value
        // of the current <input>, that we found earlier:
        (el) => el.value = value
      );
  };

getAll('td>input').forEach(
  (el) => el.addEventListener('input', onUpdate)
);
*,
 ::before,
::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

table {
  border-collapse: collapse;
  inline-size: clamp(30rem, 50vw, 900px);
  margin-block: 1em;
  margin-inline: auto;
  table-layout: fixed;
}

:is(th, td):first-child {
  width: 12ex;
}

td {
  border-block: 1px solid currentColor;
  padding-block: 0.5em;
  padding-inline: 1em;
}

td:first-child {
  border-inline-start: 1px solid currentColor;
}

td:last-child {
  border-inline-end: 1px solid currentColor;
}

tr:focus-within td {
  color: rebeccapurple;
}

input {
  color: inherit;
  inline-size: 100%;
  object-fit: cover;
}
<table>
  <thead>
    <tr>
      <th>Number</th>
      <th>Name</th>
      <th>Other</th>
      <th>Quantity</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>2</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>3</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>4</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>5</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>6</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>7</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>8</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>9</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>10</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>11</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>12</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>13</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>14</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
    <tr>
      <td>15</td>
      <td><input type="text"></td>
      <td>Other possible table contents</td>
      <td><input type="number"  placeholder="Quantity"></td>
    </tr>
  </tbody>
</table>

JS Fiddle demo.

References:

  • Related