3

My table looks like so:

enter image description here

I wrote a bit of CSS so when I hover on a specific field under a 15-year mortgage column, the corresponding cell under the 30-year mortgage is also hovered.

td:hover, td:hover + td + td + td + td {
    background-color: grey;
}

This works great when I select a 15-year mortgage field, but not when I select a 30-year mortgage field. That is, it doesn't work in the other direction.

enter image description here

The table structure is pretty straightforward:

<thead>
    <tr>
        <th colSpan='1' />
        <th colSpan='4'>15 year</th>
        <th colSpan='4'>30 year</th>
    </tr>
    <tr>
        <th colSpan='1' />
        <th>Mortgage Payment</th>
        <th>Investment Payment</th>
        <th>Loan Amount</th>
        <th>Investment Amount</th>
        <th>Mortgage Payment</th>
        <th>Investment Payment</th>
        <th>Loan Amount</th>
        <th>Investment Amount</th>
    </tr>
</thead>
<tbody>
    <tr>
        <td>Year x</td>
        <td>value</td>
        <td>value</td>
        <td>value</td>
        <td>value</td>
        <td>value</td>
        <td>value</td>
        <td>value</td>
        <td>value</td>
    </tr>
    ...
</tbody>

I've already read that there is no "previous sibling" selector in CSS so I am looking for a different solution. JavaScript solutions are fine if pure CSS can't get the job done.

jgozal
  • 1,480
  • 6
  • 22
  • 43
  • Do you want a css, html solution only or a javascript solution is fine too? – Manish Sep 11 '19 at 04:54
  • javascript is totally fine @Manish. I'm actually trying to work on a javascript solution while I wait on responses here. I'll add the js tag to the post. – jgozal Sep 11 '19 at 04:55
  • Ofcourse it won't work because the hovering is +4 td (`td + td + td + td`) if there's 45-year mortgage and you select 30-year mortgage, it will hovered there. the solution is close onto using -4 td – Shiz Sep 11 '19 at 05:30
  • @jgozal cool. Please see my answer. have posted two solutions one with javascript only and other one with jQuery which ever suits you best... – Manish Sep 11 '19 at 05:41

3 Answers3

0

I think the best solution is to add similar classes for both your tables. For example your Year 4 Mortage Payement will have year-4-mortage class for both your 15 and your 30 years tables. Then you can use a simple jQuery to add an active class to the hovered elements which will have your desired css.

$('td').hover(function(){
   // Remove the current active class
   $('td').removeClass('active');

   //Add class to desired td
   $('.'+$(this).attr('class')).addClass('active');
});

CSS:

.active {
   background-color: grey;
}
Mojo Allmighty
  • 793
  • 7
  • 18
0

Here is a javascript only solution. You can use classes and the classList and then add and remove functions. With jQuery this can be simplified even more. Here i have made an assumptions that it will always be the 4th column which is similar. To make it more generic you can tweak the code accordingly..

JavaScript Only Solution

window.onload = function() {
  tdElems = document.getElementsByTagName('td')
  tdElems = Array.prototype.slice.call(tdElems);

  tdElems.forEach((elem) => {
    elem.addEventListener('mouseleave', function($event) {
      tdElems.forEach((td) => {
        td.style.background = 'white';
      })
    });
    elem.addEventListener('mouseover', function($event) {
      showHover($event.target);
    });
  })
}



function showHover(elem) {
  parent = elem.parentElement;
  for (i = 0; i < parent.children.length; i++) {
    if (parent.children[i] === elem) {
      elem.style.background = 'lightgray';
      if (parent.children[i + 4]) {
        parent.children[i + 4].style.background = 'lightgray';
      } else if (parent.children[i - 4]) {
        parent.children[i - 4].style.background = 'lightgray';
      }
      break;
    }

  }
}
<table>
  <thead>
    <tr>
      <th colSpan='1' />
      <th colSpan='4'>15 year</th>
      <th colSpan='4'>30 year</th>
    </tr>
    <tr>
      <th colSpan='1' />
      <th>Mortgage Payment</th>
      <th>Investment Payment</th>
      <th>Loan Amount</th>
      <th>Investment Amount</th>
      <th>Mortgage Payment</th>
      <th>Investment Payment</th>
      <th>Loan Amount</th>
      <th>Investment Amount</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Year x</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
    </tr>
    <tr>
      <td>Year x</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
    </tr>
  </tbody>
</table>

Solution with jQuery

$(document).ready(function() {
  $('td').hover(function($event) {
    $('td').removeClass('hovered');
    $(this).addClass('hovered');
    const parent = this.parentElement;
    var index = Array.from(parent.children).indexOf(this);
    if (parent.children[index + 4]) {
      $(parent.children[index + 4]).addClass('hovered');
    } else if (parent.children[index - 4]) {
      $(parent.children[index - 4]).addClass('hovered');
    }

  }, function() {
    $('td').removeClass('hovered');
  });

})
.hovered {
  background: lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <thead>
    <tr>
      <th colSpan='1' />
      <th colSpan='4'>15 year</th>
      <th colSpan='4'>30 year</th>
    </tr>
    <tr>
      <th colSpan='1' />
      <th>Mortgage Payment</th>
      <th>Investment Payment</th>
      <th>Loan Amount</th>
      <th>Investment Amount</th>
      <th>Mortgage Payment</th>
      <th>Investment Payment</th>
      <th>Loan Amount</th>
      <th>Investment Amount</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Year x</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
    </tr>
    <tr>
      <td>Year x</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
      <td>value</td>
    </tr>
  </tbody>
</table>

Hope this helps :)

Manish
  • 4,692
  • 3
  • 29
  • 41
0

I ended up creating a solution myself as well. The function will fire onMouseOver in the tr element, but we could put it in the tbody as well, or really anywhere in the table.

const hoverTableCells = year => {
  // grab table cells depending on year
  const tableCells = Array.from(
    document.getElementsByTagName('tbody')[0].children[year].children
  )

  const hover = (color, cell, index) => {
    const nextCells = tableCells[index + 4]
    const prevCells = tableCells[index - 4]

    cell.style.backgroundColor = color

    if (typeof nextCells !== 'undefined') {
      nextCells.style.backgroundColor = color
    }
    if (typeof prevCells !== 'undefined') {
      prevCells.style.backgroundColor = color
    }
  }

  // iterate over all cells in row and set appropriate color depending on mouse event
  tableCells.forEach((cell, index) => {
    cell.addEventListener('mouseover', () => hover('grey', cell, index))
    cell.addEventListener('mouseleave', () => hover('white', cell, index))
  })
}

I also added logic to make sure that the Year column isn't selected, but that wasn't part of my original question so I won't be including that in this answer.

jgozal
  • 1,480
  • 6
  • 22
  • 43