Home > Software engineering >  How do I implement a date range filter on my webpage?
How do I implement a date range filter on my webpage?

Time:11-05

I have the following date pickers:

<div style="margin-bottom: 20px;">
    <label for="startDate">Start Date: </label>
    <input type="date" id="startDate"  />
    <label for="endDate">End Date: </label>
    <input type="date" id="endDate"  />
    <button onclick="filterByDate()">Filter</button>
</div>

I have a table like this:

<thead  style="top: 50px;">
    <tr>
        <th>Job No</th>
        <th>Company</th>
        <th>Permit No</th>
        <th>R No</th>
        <th>TM Company</th>
        <th>TM Type</th>
        <th>Address</th>
        <th>Checked By</th>
        <th>Checked Date</th>
        <th style="width:250px;">Comments</th>
    </tr>
</thead>        

Where I want to filter through the 'Checked Date' column in my table, which is assigned a 'TbDate' value and displayed in the DD/MM/YYYY HH:mm format:

<td>@firstJob.TbDate?.ToString("dd/MM/yyyy HH:mm")</td>

The rendered HTML of the date pickers and the table rows appear like this:

       <div style="margin-bottom: 20px;">
            <label for="startDate">Start Date: </label>
            <input type="date" id="startDate"  pattern="\d{2}/\d{2}/\d{4}">
            <label for="endDate">End Date: </label>
            <input type="date" id="endDate"  pattern="\d{2}/\d{2}/\d{4}">
            <button onclick="filterByDate()">Filter</button>
        </div>        
       
        <tr >
           <td><a href="/Job?JobNo=505248" target="_blank">505248</a></td>
           <td>SCS</td>
           <td>SMA TEST</td>
           <td>SMATEST1</td>
           <td>></td>
           <td></td>
           <td>DO NOT PLAN, THIS IS A TEST, TEST TOWN</td>
           <td>Test Name</td>
           <td>27/10/2023 12:17</td>
           <td>                                       
           <form id="CommentsBox_505248" style="display: flex; align-items: center; justify-content: flex-end; width: 100%;">
               <input type="hidden" name="JobNo" value="505248">
               <textarea name="Comments" placeholder="Add comments" style="flex: 1 1 auto; width: 100%; height: 80px; box-sizing: border-box; margin-right: 10px;"></textarea>
               <button type="button" onclick="submitComment('505248')">Submit</button>
           </form>               
           </td>            
         </tr>

How can I implement JavaScript to filter through the rows in my table between the range set in the date pickers?

I only want to filter through using the DD/MM/YYYY value and ignore the HH:mm values.

I am using Bootstrap, razor page, JQuery and Vanilla JS.

CodePudding user response:

I don't use Bootstrap or jQuery so can offer no guidance with whatever native methods they might have but with vanilla JS you could perhaps accomplish your goal like this.

The snippet below shows 3 possible table rows of dummy data based upon your edited HTML. I hope this is a reasonable facsimile of what you might see.

All inline event handlers have been moved out to a delegated listener which inspects the event.target to determine which function to run. The forms within the table probably don't need IDs and the inline styles were also moved to external css.

The filterByDate function initially checks that both start and end dates have been given values. With that filtered array of input element references we build two new Date objects and get the times for each. These times are used to compare with rows in the HTML table.

Query the DOM to find all table rows of class .row-data and find the table-cell that contains the date string value. As per comment above, this would be simpler if the table-row itself had, for example, a dataset attribute that contained this date string. The datestring is modified to create a valid string format and a new Date object is created and used for the comparison. If the table row has a date within the range given by the input elements the row will be shown, otherwise it will be hidden.

const convertdate=(str)=>{
  let [date,time]=str.split(' ');
  let [d,m,y]=date.split('/');
  return [y,m,d].join('/');
}

const filterByDate=(e)=>{
  let inputs=e.target.closest('div').querySelectorAll('input[type="date"]');
      inputs=[...inputs].filter(input=>{
        return input.value!='';
      });
      
  if( inputs.length==2 ){
    let ds=( new Date( inputs[0].value ) ).getTime();
    let df=( new Date( inputs[1].value ) ).getTime();
  
    let col=document.querySelectorAll('.data-row');
        col.forEach(tr=>{
          tr.style.display='none';
        })
        col=[...col].filter(tr=>{
          let jobdate=( new Date( convertdate( tr.querySelector('td:nth-of-type(9)').textContent ) ) ).getTime();
          
          return jobdate >= ds && jobdate <= df;
        });
        
        col.forEach( tr=>{
          tr.style.display='table-row';
        });
  }else{
    console.log('too few dates to create the upper and lower ranges')
  }
  return true;
};

const submitComment=(e)=>{
  let form=e.target.closest('form');
  return form.submit();
};


document.addEventListener('click',e=>{
  if( e.target instanceof HTMLButtonElement && e.target.classList.contains('subcom') ){
    return submitComment(e);
  }
  if( e.target instanceof HTMLButtonElement && e.target.classList.contains('filter') ){
    return filterByDate(e);
  }
});
table{
  border-collapse:none;
  font-family:monospace;
}
thead{
  background:grey;
  color:white;
}

.data-row td{
  padding:1rem;
  border:1px dotted grey;
}

textarea{
  flex: 1 1 auto; 
  width: 100%; 
  height: 80px; 
  box-sizing: 
  border-box; 
  margin-right: 10px;
}
form{
  display: flex; 
  align-items: center; 
  justify-content: flex-end; 
  width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div style="margin-bottom: 20px;">
  <label>Start Date: <input type="date"  pattern="\d{2}/\d{2}/\d{4}"></label>
  <label>End Date: <input type="date"  pattern="\d{2}/\d{2}/\d{4}"></label>
  <button class='filter'>Filter</button>
</div>


<table>
  <thead  style="top: 50px;">
    <tr>
      <th>Job No</th>
      <th>Company</th>
      <th>Permit No</th>
      <th>R No</th>
      <th>TM Company</th>
      <th>TM Type</th>
      <th>Address</th>
      <th>Checked By</th>
      <th>Checked Date</th>
      <th style="width:250px;">Comments</th>
    </tr>
  </thead>
  <tbody>
    <tr >
      <td><a href="/Job?JobNo=505248" target="_blank">505248</a></td>
      <td>MAY</td>
      <td>SMA TEST</td>
      <td>SMATEST1</td>
      <td>&gt;</td>
      <td></td>
      <td>TEST TOWN</td>
      <td>Test Name</td>
      <td>01/05/2023 12:17</td>
      <td>
        <form>
          <input type="hidden" name="JobNo" value="505248">
          <textarea name="Comments" placeholder="Add comments"></textarea>
          <button  type="button">Submit</button>
        </form>
      </td>
    </tr>


    <tr >
      <td><a href="/Job?JobNo=63457456" target="_blank">63457456</a></td>
      <td>NOV</td>
      <td>SMA TEST</td>
      <td>SMATEST1</td>
      <td>&gt;</td>
      <td></td>
      <td>TEST TOWN</td>
      <td>Test Name</td>
      <td>22/11/2023 16:22</td>
      <td>
        <form>
          <input type="hidden" name="JobNo" value="63457456">
          <textarea name="Comments" placeholder="Add comments"></textarea>
          <button  type="button">Submit</button>
        </form>
      </td>
    </tr>
    
    <tr >
      <td><a href="/Job?JobNo=5052456" target="_blank">5052456</a></td>
      <td>SEPT</td>
      <td>SMA TEST</td>
      <td>SMATEST1</td>
      <td>&gt;</td>
      <td></td>
      <td>TEST TOWN</td>
      <td>Test Name</td>
      <td>5/09/2023 12:30</td>
      <td>
        <form>
          <input type="hidden" name="JobNo" value="5052456">
          <textarea name="Comments" placeholder="Add comments"></textarea>
          <button  type="button">Submit</button>
        </form>
      </td>
    </tr>
  </tbody>
</table>

CodePudding user response:

I think your date format is wrong.

Your 'checkedAt' date is formatted like dd/MM/yyyy HH:mm, so you can't create new date using your 'checkedAt' date.

Usually, the date string is formatted like this : MM/dd/yyyy HH:mm.

If you change format of 'checkedAt' like this, you can solve your problem more easily.

const originalData = []; //your dataList in table
const startAt = new Date(document.getElementById("startDate").value);
const endAt = new Date(document.getElementById("endDate").value);

const filteredData = originalData.filter((data) => {
  const checkedAt = new Date(data.checkDate);
  return checkedAt > startAt && checkedAt < endAt;
});

//you get filtered data list : filteredData

I hope this answer will help you.

  • Related