0

I have a table with users and want the action buttons to work on the <tr> they are children of. When one of the buttons calls a javascript function, I want the function to store the <tr> element in a variable so I can work with just the one that holds the button and not affect any other <tr> elements. ps: I can use jQuery!
My code:

function editUser() {
  /*
  var button = *the button clicked*;
  var tr = button.getParent(get the <tr> in some way);
  editSomething(tr);
  */
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

tr:nth-child(even) td {
  border: 1px solid #cbcbcb;
}

#search {
  padding-bottom: 5vw;
}

.actionLink {
  border: 1px solid black;
  padding: 2px;
}

.actionLink:hover {
  cursor: pointer;
  background-color: black;
  color: white;
}
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a onclick="editUser()" class="actionLink">Quick Edit</a>
        <a onclick="editUser()" class="actionLink">View</a>
        <a onclick="editUser()" class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

1
  • Are you using straight Javascript or do you have JQuery installed? This could change the answer you receive. Commented May 4, 2018 at 14:52

6 Answers 6

3

You can use element.parentNode like .parentNode.parentNode from current element a:

function editUser(thatTR) {
  var tr = thatTR.parentNode.parentNode
  editSomething(tr);
  
}
function editSomething(tr){
  console.log(tr)
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

tr:nth-child(even) td {
  border: 1px solid #cbcbcb;
}

#search {
  padding-bottom: 5vw;
}

.actionLink {
  border: 1px solid black;
  padding: 2px;
}

.actionLink:hover {
  cursor: pointer;
  background-color: black;
  color: white;
}
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a onclick="editUser(this)" class="actionLink">Quick Edit</a>
        <a onclick="editUser(this)" class="actionLink">View</a>
        <a onclick="editUser(this)" class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

OR: You can use .closest('tr'):

function editUser(thatTR) {
  var tr = thatTR.closest('tr');
  editSomething(tr);
}
function editSomething(tr){
  console.log(tr);
}
    table {
      font-family: arial, sans-serif;
      border-collapse: collapse;
      width: 100%;
    }

    td,
    th {
      border: 1px solid #dddddd;
      text-align: left;
      padding: 8px;
    }

    tr:nth-child(even) {
      background-color: #dddddd;
    }

    tr:nth-child(even) td {
      border: 1px solid #cbcbcb;
    }

    #search {
      padding-bottom: 5vw;
    }

    .actionLink {
      border: 1px solid black;
      padding: 2px;
    }

    .actionLink:hover {
      cursor: pointer;
      background-color: black;
      color: white;
    }
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a onclick="editUser(this)" class="actionLink">Quick Edit</a>
        <a onclick="editUser(this)" class="actionLink">View</a>
        <a onclick="editUser(this)" class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

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

4 Comments

This only gonna work for the this structure : tr -> td -> the clicked element
@ElAoutarHamza which it is
@ElAoutarHamza, do you see any other structure in OP's code?
What I meant, is that the solution isn't generic. For example if OP want to group all the a tags inside a div or even use that event handler for td, then I don't see how this will work
1

You can use closest :

function editUser(e) {
    let tr = e.closest('tr'); 
}

<tr>
  <td>
    <a onclick="editUser(this)" class="actionLink">Quick Edit</a>
    <a onclick="editUser(this)" class="actionLink">View</a>
    <a onclick="editUser(this)" class="actionLink">Delete</a>
  </td>
</tr>

2 Comments

Alas not supported cross browser
@mplungjan true ! not gonna work on IE according to MDN
1

You can simply add an EventListener for clicks to all elements with the actionLink class, and then get the TR with element.parentElement.parentElement since it's the parent of the parent of the link:

document.querySelectorAll(".actionLink").forEach(e => e.addEventListener("click", editUser));

function editUser(e) {
  let tr = (e.target.parentElement.parentElement);
  // doSomethingWith(tr);
}

Or, complete:

document.querySelectorAll(".actionLink").forEach(e => e.addEventListener("click", editUser));

function editUser(e) {
  let tr = (e.target.parentElement.parentElement);
  // doSomethingWith(tr);
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

tr:nth-child(even) td {
  border: 1px solid #cbcbcb;
}

#search {
  padding-bottom: 5vw;
}

.actionLink {
  border: 1px solid black;
  padding: 2px;
}

.actionLink:hover {
  cursor: pointer;
  background-color: black;
  color: white;
}
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a class="actionLink">Quick Edit</a>
        <a class="actionLink">View</a>
        <a class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

Comments

1

Have a try with this. It is unobtrusive - i.e. no inline script used

jQuery (since you said you could use it):

$(".actionLink").on("click",function() {
    alert($(this).text() + "("+$(this).closest("tr")+")"); 
})
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

tr:nth-child(even) td {
  border: 1px solid #cbcbcb;
}

#search {
  padding-bottom: 5vw;
}

.actionLink {
  border: 1px solid black;
  padding: 2px;
}

.actionLink:hover {
  cursor: pointer;
  background-color: black;
  color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a class="actionLink">Quick Edit</a>
        <a class="actionLink">View</a>
        <a class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

Plain JS (with an IE compatible closest):

// element.closest() is not supported by IE at all
var getClosestTr = function(elem) { for ( ; elem && elem !== document; elem = elem.parentNode ) { if (elem.tagName=="TR") return elem;} return null; };

document.querySelectorAll(".actionLink").forEach(function(link) {
  link.onclick=function() {
    alert(this.innerText + "("+getClosestTr(this)+")"); // or this.closest("tr") where supported
  }
})
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

tr:nth-child(even) td {
  border: 1px solid #cbcbcb;
}

#search {
  padding-bottom: 5vw;
}

.actionLink {
  border: 1px solid black;
  padding: 2px;
}

.actionLink:hover {
  cursor: pointer;
  background-color: black;
  color: white;
}
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a class="actionLink">Quick Edit</a>
        <a class="actionLink">View</a>
        <a class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

2 Comments

doesn't work for some reason, neither the jQuery or plain js
It works here with your html. If your html is not the same as here, then perhaps not? I pass the TR object to the function - in jQuery it is a jQuery object
1

Well, if getting parent tr is only thing that you really need, you can access it using parentElement of event target. Take a look at modified snippet:

function editUser(button) {
  const tr = button.parentElement.parentElement
  console.log(tr)

}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}

tr:nth-child(even) td {
  border: 1px solid #cbcbcb;
}

#search {
  padding-bottom: 5vw;
}

.actionLink {
  border: 1px solid black;
  padding: 2px;
}

.actionLink:hover {
  cursor: pointer;
  background-color: black;
  color: white;
}
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Username</th>
      <th>Rank</th>
      <th>Points</th>
      <th>Status</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Gamanware</td>
      <td>Owner</td>
      <td>0</td>
      <td>Online</td>
      <td>
        <a onclick="editUser(this)" class="actionLink">Quick Edit</a>
        <a onclick="editUser(this)" class="actionLink">View</a>
        <a onclick="editUser(this)" class="actionLink">Delete</a>
      </td>
    </tr>
  </tbody>
</table>

2 Comments

If you pass the anchor, why pass the event? The target IS the anchor
@mplungjan Indeed... But it may happen, that you need to do something with event. In this particular example it may be overkill.
0

Set an id for each <tr> and pass it in the function editUser(id).

Then inside the function just check which is the caller tr and only change it using the id for the selector.

1 Comment

That is not very generic

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.