Dipzera
Dipzera

Reputation: 95

How to filter HTML data based on date in JavaScript?

Let's expect I have a table with a lot of rows. The rows data is from server.

<table>
  <tr data-date="${date}"> // let's assume this is from server
    <td>Code</td>
    <td>${date}</td>
    <td>Name</td>
  </tr>
  <tr data-date="${date}>
    <td>Code</td>
    <td>${date}</td>
    <td>Name</td>
  </tr>
</table>

I also have 3 buttons that look like this:

<button>currentday</button>
<button>currentweek</button>
<button>currentmonth</button>

I want when one of the buttons have the class active for example, to show in the table the only rows with the corresponding date. Let's assume I pressed day, then I show in my table the rows that have the data-date matching the data-date of the day button. And if I press week or month, I check all the table rows data-date that are in between the week or month (that match).

Upvotes: 0

Views: 2766

Answers (2)

When it's said it's supposed to "show in the table the elements with the corresponding date.", I assume that means there is a table, AKA some table HTML sent from the server and stored as a string (or variable) somewhere with all of the possible dates, and I'm also guessing that the buttons are used to somehow select a specific date, I'm imagining a calendar-style app, where there is a current day shown, and one can change the week by click on the week button, etc., but let me know if this is something else.

Anyways the main point of the question is "how to filter HTML data based on date in javascript", by "html data" I assume that means to show and hide certain HTML, based on the innerHTML value of some of the elements contents.

To do that, you need to start with the value you are searching for. For example, let's use the string "02-07-2020", generated one way or another, and you have an entire table of dates, I'm assuming you received the string of this table from the server and have it stored in JavaScript, if not them I'm assuming the server sent back the raw HTML onto the page and you want to JavaScript to filter the HTML table (AKA remove all rows that don't correspond to the string) when a button is pressed. Either way it should be the same.

So assuming there is a table with all of the dates already in HTML, and you want to "hide" (/I'm assuming that means remove) all cells whose contents don't correspond with the date, then you have a couple different options.

Either, you can manually call the deleteCell() method on all of the cells that don't contain the value, (but then you would have to regenerate all of those cells that DO contain the next value anyways) or you can generate the entire table with JavaScript on each button press, and only generate the cells you want, or the most preferred option (which I assume you're asking about anyways) is to add display:none to the style of the surrounding tr elements, the only problem is how to find what specific data to filter through, but this should be trivial.

Ok so we're going to go with the 3rd method, and to do this we simply need 3 inputs, we need what day we're searching for, what week, and what month (I assume, as mentioned in the comments, that day means the full date, week means a particular week only, and month means an entire month, so each one is less inclusive than the last, so we also need a variable input to tell us which one we are searching for).

OK so basically we just need to supply two main inputs into our function, a start date and an end date, and if there is no end date, assume we are looking for only the start date

So I'm in america so I'm used to american dates, but it seems from the question that it is using the european format, with the day before the month, so that will complicate our use of the built in Date API a bit, but it should still be fine, we just need to either manually make our own proto-date system to check if one string is in between two others, or extract the day-week-month from the string using .split(-) and generate a new string or use with the native Date API, but either way it should work out.

OK so let's get started:

doIt.onclick = () => {

  var startDate = dateStart.value,
        endDate = dateEnd.value;
  sortThroughTable(startDate, endDate)
 
};

function sortThroughTable(start, end) {
  Array.apply(0, myTable.rows).forEach(x => {
    var cells = Array.apply(0, x.cells);
    var secondCell = cells[1].innerText;
    var isHidden = shouldItBeHidden(
      secondCell,
      start, end
    );
    if(isHidden) {
      x.style.display = "none"
    } else if(x.style.display == "none")
      x.style.display = "";
  })
  
  function shouldItBeHidden(
    cellTxt,
    start,
    end
  ) {
    var parsedCell = myParse(cellTxt),
        parsedStart = myParse(start),
        parsedEnd = myParse(end);
    return !(
    //here's where the real logic is
      parsedCell ? 
        (parsedStart && parsedEnd) ?
          isDateGreaterOrEqual(parsedCell, parsedStart) &&
          isDateGreaterOrEqual(parsedEnd, parsedCell)
        : 
          parsedStart &&
            cellTxt == start
      : false
      
    )

  }
  
  function isDateGreaterOrEqual(parsedDate, otherParsedDate) {
    var isYearGreater = (
      parsedDate.year >
      otherParsedDate.year
    ),
        isMonthGreater = (
      parsedDate.month >
      otherParsedDate.month
    ),
        isDayGreater = (
      parsedDate.day >
      otherParsedDate.day
    ), 
    
        isYearSame = (
      parsedDate.year ==
      otherParsedDate.year
    ),
        isMonthSame = (
      parsedDate.month ==
      otherParsedDate.month
    ),
        isDaySame = (
      parsedDate.day ==
      otherParsedDate.day
    );
    
    if(isYearGreater) {
      return true;
    } else if(isYearSame) {
    
     if(isMonthGreater) {
        return true;
     } else if(isMonthSame) {
     
        if(isDayGreater) {
          return true;
        } else return isDaySame;
        
     } else return false;
     
    } else return false;
  }
  
  function myParse(str) {
    return (splat => 
      splat.length == 3 &&
      !splat.find(x => isNaN(x)) ? 
      Object.fromEntries(
        (list => splat
          .map((x, i) => (
            [list[i], parseInt(x)]
          ))
        )([
          "day", "month", 
          "year"
        ])
      ) : null
    )(
      typeof(str) == "string" ? 
        str.split("-")
      : []
    )
  }
}
<table id=myTable>
  <tr>
    <td>Code</td>
    <td>02-07-2020</td>
    <td>Name</td>
  </tr>
  <tr>
    <td>Code</td>
    <td>25-06-2020</td>
    <td>Name</td>
  </tr>
</table>
<!--don't know how 
the library is set up but I'm just gonna 
do it by manually entering the strings to 
an input, you can adapt it to whatever you want
-->

<input id="dateStart" value="24-06-2020">
<input id="dateEnd" value="26-06-2020">

<button id=doIt>filter!</button>

Upvotes: 0

Karol Pawlak
Karol Pawlak

Reputation: 464

I assume that:

  1. "day" means todays date,
  2. "week" means date range since first to last day of current week
  3. "month: means date range since first to last day of current month

So if today is 2020-07-02:

  1. day would give "2020-07-02"
  2. week would give range 2020-06-29 (if monday is first day of week) to 2020-07-05 (if sunday is last day of week)
  3. month would give range 2020-07-01 to 2020-07-31

In JavaScript, according to this thread

let currentDate = new Date(); //returns todays date

currentDate.getDate() // returns day of current month
currentDate.getDay() // returns day of current week (sun = 0, mon = 1)

let firstDayOfCurrentWeek = currentDate.getDate() - currentDate.getDay()
let lastDayOfCurentWeek = firstDayOfCurrentWeek + 6; // assuming, sunday is first day of week

firstDayOfCurrentWeek = new Date(currentDate.setDate(firstDayOfCurrentWeek ));
lastDayOfCurentWeek = new Date(currentDate.setDate(lastDayOfCurentWeek));

Its much easier to get range of first and last day of month:

let firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); 
let lastDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);

You need to mark cells containing dates somehow:

<table id="mytab">
  <tr>
    <td>Code</td>
    <td class="date">02-07-2020</td>
    <td>Name</td>
  </tr>
  <tr>
    <td>Code</td>
    <td class="date">25-06-2020</td>
    <td>Name</td>
  </tr>
</table>

Now, when you have all required dates for your buttons, simply read date from your table cells and check which ones matches range, and hide the rest.

var table = document.getElementById("mytab");
for (var i = 0, row; row = table.rows[i]; i++) {
   for (var j = 0, col; col = row.cells[j]; j++) {

    if (col.classList.contains("date")) {
        let control_date = col.innerHTML.split('-');

        control_date = new Date(control_date [2], control_date[1] , control_date[0]);

        if (control_date == currentDate) {
            //this cell date is todays date

        }
        
        if (control_date > firstDayOfCurrentWeek && control_date < lastDayOfCurentWeek) {
            //this cell date is in this week date
        }

        if (control_date > firstDayOfMonth && control_date < lastDayOfMonth) {
            //this cell date is in this monthdate
        }

    }
   }  
}

Please note, that date can match more than one range eg. todays date will match today, wee, and month at the same time

Upvotes: 2

Related Questions