Home > Software design >  Issue trying dynamically color code rows based on the hour
Issue trying dynamically color code rows based on the hour

Time:02-22

I'm working on a JS project where I create a daily scheduler and each hour should be color coded based on if it is past, present, or the future.

The schedule goes from 9am to 5pm. Currently it is applying the class for future to every block, so every row shows up as green. Instead, say if it were 11am, then the row for 11am would be highlighted red for present time, the rows for the hours before 11am would be grey or transparent and the hours in the future would be green.

I have set Ids for each of my hour blocks to parse through and compare with the current hour, but for some reason it isn't working. I already have the classes set up in my CSS for past present and future.

var blocks = document.getElementsByClassName("description");
var hourBlock = parseInt(moment().format('H'));


Array.from(blocks).forEach(description => {
  let idString = description.id, rowHour;
  
  if (idString) {
    rowHour = parseInt(idString);
  }
  
  if (rowHour) {
    if (hourBlock === rowHour) {
      $(".description").addClass("present")
    } else if (hourBlock < rowHour) {
      $(".description").addClass("past")
    } else {
      $(".description").addClass("future");
    }
  }
});

CodePudding user response:

The issue is because in your loop you're updating the classes of all .description elements, not the one in the forEach loop.

To fix the problem, and make your code much more succinct, you can pass a function to jQuery's addClass() method which will be evaluated against every element in the collection individually. In this function you can check the id of the element against the current hour (which you don't need MomentJS for) and set the appropriate class. Try this:

// let nowHour = (new Date()).getHours();
let nowHour = 13; // hard-coding value for this demo
$('.description').addClass(function() {
  return  this.id === nowHour ? 'present' :  this.id < nowHour ? 'past' : 'future'; 
});
.present { background-color: #C00; }
.past { background-color: #CCC; }
.future { background-color: #0C0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div  id="9">9am</div>
<div  id="10">10am</div>
<div  id="11">11am</div>
<div  id="12">12pm</div>
<div  id="13">1pm</div>
<div  id="14">2pm</div>
<div  id="15">3pm</div>
<div  id="16">4pm</div>
<div  id="17">5pm</div>

CodePudding user response:

Any time you call code like this:

$(".description").addClass("past");

...it will query ALL the elements with class 'description' as set the class to past. What you want to do is only set the class of the element being examined in the loop.

Since you're using jquery, we don't need getElementsByClassName('description') because this is translatable as $('.description').

// using jquery's each to loop through the collection
$('.description').each((idx, elt) => {
   $(elt).removeClass(); // no params to clear ALL classes from element
   // put whatever logic you want to analyze the element (elt)
   $(elt).addClass("whateverClassYouWant");
   // add the description back on, or don't remove it and instead removeClass('specificClass') for each past/present/future
   $(elt).addClass("description");
});

In your code you never remove the classes, you just keep adding them. It's plausible that you have assigned the correct classes to your elements, but since you never removed the incorrect classes (or all the elements have all the classes!) so then CSS had to choose which color overrides the other bases on internal priority.

You don't want any ambiguity - each item should have only the 1 class it needs, so the .removeClass() call with no parameter will remove all classes before you add the desired one back on.

CodePudding user response:

The HTML wasn't posted so I used the most appropriate tags: <table> and it's children tags. Just gather all <th> into an array then iterate through them and the callback is just an if/if else flow control statements to determine className assignment. The hour was determined by the real time.

let t = new Date()
let hour = t.getHours();
const cols = [...document.querySelectorAll('th')];
cols.forEach(h => h.className = '');
cols.forEach((h, i) => {
  if (i   9 < hour) {
    h.className = 'past';
  } else if (i   9 > hour) {
    h.className = 'future';
  } else {
    h.className = 'present';
  }
});
.past {
  background: grey
}

.future {
  background: green
}

.present {
  background: red
}
<table>
  <thead>
    <tr>
      <th>9AM</th>
      <th>10AM</th>
      <th>11AM</th>
      <th>12PM</th>
      <th>1PM</th>
      <th>2PM</th>
      <th>3PM</th>
      <th>4PM</th>
      <th>5PM</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
      <td>&nbsp;</td>
    </tr>
  </tbody>
</table>

  • Related