How to change color of an html table cell when mouse is down, based on which cell it is hovering over?

1.1k Views Asked by At

Essentially, I want a user to be able to click and hold down their mouse and scroll over any number of cells in the table, as soon as they scroll over a cell it should change color. The thing is that when the user regularly clicks a cell I want the cell to change color, and I have a separate event listener that does that.

This is my table in html

<table class="c-table" onmousedown="hoverColorFill()">

and this is the js function I made to try to handle the hover on mousedown situation I described this:

function hoverColorFill(){
    elements = document.querySelectorAll(':hover');
    for(let i=0; i<elements.length; i++){
    elements[i].style.backgroundcolor = colorEl.value
       }
}

this is the code I have for when someone simply clicks I cell:

table.addEventListener('click', (event) => {
  const rows = document.querySelectorAll('tr');
  const rowsArray = Array.from(rows);
  const rowIndex = rowsArray.findIndex(row => row.contains(event.target));
  const columns = Array.from(rowsArray[rowIndex].querySelectorAll('td'));
  const columnIndex = columns.findIndex(column => column == event.target);
  document.querySelector(".c-table").tBodies[0].rows[rowIndex-1].cells[columnIndex].style.backgroundColor = colorEl.value
})

it doesn't seem that the hoverColorFill() function works, when I drag my mouse over my table the function gets called (it can print to the console) but it doesn't change the colors. My click event listener function completely properly, but it does occasionally give this error: Uncaught TypeError: Cannot read properties of undefined (reading 'style')at HTMLTableElement. but the function that is not working doesn't throw any errors.

Edit: the reason I am not using an eventListener here is because I couldn't figure out how to do it so that it pays attention to both the hover and the mouseover.

2

There are 2 best solutions below

2
Anuja Nimesh On BEST ANSWER

colorTd() function checks if you've clicked on a td and then adds a class to it
It'll active when you click on it or drag your mouse along when you're clicking
Whether you're dragging your mouse while clicked is checked by onmousedown and onmouseup. It is stored in mouseIsDown

When you're mouse is over the table (determined by onmouseover ) and when mouseIsDown is true, colorTd() function will execute, giving tds a class

const table = document.querySelector("table");
const className = "selected";
let mouseIsDown = false;

const colorTd = (e) => (e.target.tagName = "TD" && e.target.classList.add("selected"));
table.onclick = (e) => colorTd(e);

document.onmousedown = (e) => {
  mouseIsDown = true;
  colorTd(e);
};

document.onmouseup = () => (mouseIsDown = false);
table.onmouseover = (e) => mouseIsDown && colorTd(e);
td {
  cursor: pointer;
  font-size: 22px;
}

td.selected {
  background-color: lightblue;
}

table::selection,
tr::selection,
td::selection {
  background-color: transparent;
}
<table>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
</table>

2
A Haworth On

The code for coloring a cell seems quite complex.

This snippet just adds a class to the element.

There does however need to be a bit more complexity about remembering when the mouse is down, and therefore coloring is to take place on mousemove, and to remember when the mouse is up.

The up and down events might take place outside the table so are sensed on the whole document.

Also, when moving the mouse when it is down the default in the browser is usually to add a background color (the user is thought to be doing a selection). This snippet sets this to transparent for the table so it's easier to see the coloring as it is happening.

const table = document.querySelector('table');
let mouseIsDown = false;
table.addEventListener('click', function() {
  event.target.classList.add('colorCell');
});
document.addEventListener('mousedown', function() {
  mouseIsDown = true;
  event.target.classList.add('colorCell');
})
document.addEventListener('mouseup', function() {
  mouseIsDown = false;
});
table.addEventListener('mouseover', function() {
  if (mouseIsDown) event.target.classList.add('colorCell');
});
td.colorCell {
  background-color: yellow;
}

table::selection,
tr::selection,
td::selection {
  background-color: transparent;
}
<table>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
  <tr>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
    <td>Cell</td>
  </tr>
</table>