Adding on mouseover action to every row in table

Viewed 582

I have versy simple table in html like below:

<table>
    <tbody id="myTable">

    </tbody>
</table>

I am adding rows dynamicly from json file like:

<script>

    fetch("data.json")
    .then(response => response.json())
    .then(data => {
      let table = document.getElementById("myTable");
      for(let i = 0; i < data.length; i++){
        table.innerHTML +=
        `<tr>
          <td>${data[i].title}</td>
          <td>${data[i].country}</td>
          <td>${data[i].writer}</td>
          <td>${data[i].genre}</td>
        </tr>`;
      };
    });
</script>

Could you tell me how can I add action onmouseover for every row? This action should show very simple popup with data from data[i].details.

2 Answers

You can add a fourth column to be toggled using CSS containing the details of each item:

const data = [
  { title:"title1", country:"country1", writer:"writer1", genre:"genre1", details:"details1" },
  { title:"title2", country:"country2", writer:"writer2", genre:"genre2", details:"details2" },
  { title:"title3", country:"country3", writer:"writer3", genre:"genre3", details:"details3" },
];

const table = document.getElementById("myTable");
let htmlContent = "";

for(let i = 0; i < data.length; i++) {
  htmlContent +=
    `<tr class="tableRow tooltip">
       <td>${data[i].title}</td>
       <td>${data[i].country}</td>
       <td>${data[i].writer}</td>
       <td>${data[i].genre}</td>
       <td class="tooltiptext">${data[i].details}</td>
     </tr>`;
}

table.innerHTML = htmlContent;
.tooltip .tooltiptext {
  visibility: hidden;
  width: 120px;
  background-color: black;
  color: #fff;
  text-align: center;
  padding: 5px 0;
  border-radius: 6px;
  position: absolute;
  z-index: 1;
}
.tooltip:hover .tooltiptext {
  visibility: visible;
}
<table>
    <tbody id="myTable">
    </tbody>
</table>

Also, as mentioned in the comments, it's better to concatenate the content and then append it once.

References: https://www.w3schools.com/css/css_tooltip.asp

Adding listeners programmatically

If you do want to use listeners you can add them during your data iteration by explicitly creating a <tr> element using document.createElement() and adding your listener to the returned element.

for (let i = 0; i < data.length; i++) {
  let tr = document.createElement("tr");
  tr.innerHTML =
   `<td>${data[i].title}</td>
    <td>${data[i].country}</td>
    <td>${data[i].writer}</td>
    <td>${data[i].genre}</td>`
  tr.addEventListener('mouseover', () => toggleDetails(datum.details));
  table.appendChild(tr);
};

const data = [
  { title: 'Title1', country: 'Country1', writer: 'Author1', genre: 'Romance', details: 'Details1' },
  { title: 'Title2', country: 'Country2', writer: 'Author3', genre: 'Mystery', details: 'Details2' }
]

function toggleDetails(details) {
  console.log(details);
  // show/hide tooltip
}

let table = document.getElementById("myTable");

data.forEach(datum => {
  let tr = document.createElement("tr");
  tr.innerHTML = 
      `<td>${datum.title}</td>
       <td>${datum.country}</td>
       <td>${datum.writer}</td>
       <td>${datum.genre}</td>`;
  tr.addEventListener('mouseover', () => toggleDetails(datum.details));
  table.appendChild(tr);
});
td {
  border: 1px solid black;
}
<table>
    <tbody id="myTable">

    </tbody>
</table>


Using a data attribute and ::after pseudo-element

A straight forward solution which doesn't involve adding listeners or adding HTML elements that aren't intended to be seen is to store the details in a data attribute and display this using an ::after pseudo-element on hover.

const data = [
  { title: 'Title1', country: 'Country1', writer: 'Author1', genre: 'Romance', details: 'Details1' },
  { title: 'Title2', country: 'Country2', writer: 'Author3', genre: 'Mystery', details: 'Details2' }
]

function toggleDetails(details) {
  console.log(details);
  // show/hide tooltip
}

let
  table = document.getElementById("myTable"),
  tableHTML = '';

data.forEach(datum => {
  tableHTML +=
    `<tr data-details="${datum.details}">
      <td>${datum.title}</td>
       <td>${datum.country}</td>
       <td>${datum.writer}</td>
       <td>${datum.genre}</td>
    </tr>`;
});

table.innerHTML = tableHTML;
td {
  border: 1px solid black;
}

tr:hover::after {
  content: attr(data-details);
  padding: 2px;
  background-color: tomato;
  
}
<table>
    <tbody id="myTable">

    </tbody>
</table>

Related