0

I've hardly used javascript and I'm stuck:

I've got a table with id JamTable

I'm trying to write some JS that will get me an array of each <td> value for any row clicked on, so that I can present it in a popup, wing it back to the server via POST request using an ajax call and then update the elements on the table so no postback is required - but so far I can't even get an array populated.

I've got:

    $(document).ready(function () {

        // Get all table row elements <tr> in table 'JamTable' into var 'tr'
        var tr = $('#JamTable').find('tr');

        // Bind a 'click' event for each of those <tr> row elements
        tr.bind('click', function (e) {
            // so that when a row is clicked:
            
            var r = $(this).closest('tr').row;
            var myArray = new Array(r.cells);

            for (var c = 0, col; col = r.cells[c]; c++) {
                alert(col.text)
            }
        });
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="JamTable">
      <tbody>
          <tr>
              <td>1</td>
              <td>JAM</td>
              <td>0.004</td>
          </tr>
          <tr>
              <td>3</td>
              <td>BOB</td>
              <td>0.24</td>
          </tr>
          <tr>
              <td>9</td>
              <td>Nasty Simon</td>
              <td>94.3</td>
          </tr>
      </tbody>
    </table>

Yeah I'm totally lost when it comes to JS

4 Answers 4

1

Using proper event-delegation is key to success in such scenarios. Catching "click" events on rows is guaranteed to work, even with dynamically-added rows (which were added to the DOM after the event listener was defined)

Breakdown (see comments):

const tableElm = document.querySelector('table')

// listen to "click" event anywhere on the <table>
tableElm.addEventListener('click', onTableClick)

function onTableClick(e){
  // event delegation 
  const rowElm = e.target.closest('tr')

  // traverse each child of the row (HTMLCollection). map the text value into an Array
  // https://stackoverflow.com/a/34250397/104380
  const values = rowElm ? [...rowElm.children].map(td => td.innerText) : []

  // print result
  console.clear()
  console.log(  values  )
}
<table>
  <tbody>
    <tr>
      <td>1</td>
      <td>JAM</td>
      <td>0.004</td>
    </tr>
    <tr>
      <td>3</td>
      <td>BOB</td>
      <td>0.24</td>
    </tr>
    <tr>
      <td>9</td>
      <td>Nasty Simon</td>
      <td>94.3</td>
    </tr>
  </tbody>
</table>

You should probably also have some unique id on the <tr> if you are sending data back to the server, it might need to know to which row it belongs to

Sign up to request clarification or add additional context in comments.

1 Comment

I've went for this answer as it most closely reflects my original attempt so is easiest to understand, while optimising performance
1

You can delegate the event from tr. On click of it get the children. Using Array.from will create an array of td. Using map to iterate that and get the text from the td

$("#JamTable").on('click', 'tr', function(e) {
  let k = Array.from($(this).children()).map((item) => {
    return item.innerHTML;
  })
  console.log(k)

})
td {
  border: 1px solid green;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id='JamTable'>
  <tbody>
    <tr>
      <td>1</td>
      <td>JAM</td>
      <td>0.004</td>
    </tr>
    <tr>
      <td>3</td>
      <td>BOB</td>
      <td>0.24</td>
    </tr>
    <tr>
      <td>9</td>
      <td>Nasty Simon</td>
      <td>94.3</td>
    </tr>
  </tbody>


</table>

1 Comment

no need for the return statement if you are already using arrow-function. Also no need to sometimes use function(e) and sometimes arrow-function
1

You don't need jquery for that.

You may use querySelectorAll to get the trs and simply children on the tr node to get the tds

const trs = [...document.querySelectorAll('tr')]
trs.forEach(tr => tr.addEventListener('click', e => {
  // whenever it is clicked, get its tds
  const values = [...tr.children].map(td => td.innerText)
  console.log('click', values)
}, false))
<table>
  <tbody>
    <tr>
      <td>1</td>
      <td>JAM</td>
      <td>0.004</td>
    </tr>
    <tr>
      <td>3</td>
      <td>BOB</td>
      <td>0.24</td>
    </tr>
    <tr>
      <td>9</td>
      <td>Nasty Simon</td>
      <td>94.3</td>
    </tr>
  </tbody>
</table>

As @vsync suggested, better to use event delegation in case you have a lot of rows to avoid binding several clicks. This also allows to add more rows later on without to have to bind more click handler

edit2 still thx to @vsync, avoid using onclick and prefer addEventListener to avoid overriding existing events

const table = document.querySelector('table')
table.addEventListener('click', e => {
  if (e.target.nodeName !== 'TD') { return }
  const values = [...e.target.parentNode.children].map(c => c.innerText)
  console.log(values)
}, false)
<table>
  <tbody>
    <tr>
      <td>1</td>
      <td>JAM</td>
      <td>0.004</td>
    </tr>
    <tr>
      <td>3</td>
      <td>BOB</td>
      <td>0.24</td>
    </tr>
    <tr>
      <td>9</td>
      <td>Nasty Simon</td>
      <td>94.3</td>
    </tr>
  </tbody>
</table>

3 Comments

Very good, but not optimal, not using event delegation is never recommended.
You should also never ever bind events without addEventListener, it will override previous event that might have been there.
Well spotted, I'll have a lot of rows so don't want to bind to all of them if I can just check the click target instead.
0

$('#JamTable tbody tr').click(function () {
    var arr = [];
    $($(this).children('td')).each(function (index, val) {
        arr.push(val.innerText);
    });
    console.log(arr);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="JamTable">
    <tbody>
        <tr>
            <td>1</td>
            <td>JAM</td>
            <td>0.004</td>
        </tr>
        <tr>
            <td>3</td>
            <td>BOB</td>
            <td>0.24</td>
        </tr>
        <tr>
            <td>9</td>
            <td>Nasty Simon</td>
            <td>94.3</td>
        </tr>
    </tbody>
</table>

1 Comment

no need to write .children('td') because only <td> elements can be a child of rows inside <tbody>, so writing .children() is suffice, Also, it's best-practice to utilize event-delegation method, if possible. See my answer for details

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.