0

I have a table and a dropdown list whose options are created by a javascript code with two options - 2018 and 2019.

i need a code to display ONLY the table rows with the selected year and set it up in order by date, then hour.

first table cell: date (dd/mm/yyyy) second table cell: hour (24h format)

var select = document.getElementById("year");
var options = ["2018", "2019"];

for (var i = 0; i < options.length; i++) {
  var opt = options[i];
  var el = document.createElement("option");
  el.textContent = opt;
  el.value = opt;
  select.appendChild(el);
}
<select id="year">

</select>

<table>
  <tbody>
    <tr>
      <td>06/05/2018</td>
      <td>16:00h</td>
      <td>Chris</td>
    </tr>

    <tr>
      <td>24/10/2019</td>
      <td>20:00h</td>
      <td>Alex</td>
    </tr>

    <tr>
      <td>11/03/2018</td>
      <td>15:00h</td>
      <td>Dani</td>
    </tr>

    <tr>
      <td>08/04/2019</td>
      <td>12:30h</td>
      <td>Joe</td>
    </tr>

    <tr>
      <td>22/04/2018</td>
      <td>10:30h</td>
      <td>Mike</td>
    </tr>
  </tbody>
</table>
Alexandre Elshobokshy
  • 10,720
  • 6
  • 27
  • 57
Gustavo Alves
  • 49
  • 2
  • 9

5 Answers5

1

You tagged it jQuery so I propose the code below.

It includes a sort and the year select is generated from table content

var options = [];

// create a valid date from the first two cells
function makeDate(row) {
  var date = $("td",row).eq(0).text(), 
      time = $("td",row).eq(1).text().substring(0,5);
  date = date.split(/\//).reverse().join('/');   
  var year = date.split("/")[0];
  if (options.indexOf(year) ==-1) options.push(year);
  var dateString = date + " " + time;
  return Date.parse(dateString);
}

$(function() {
  var $select = $("#year");

  // sort the table before showing it
  // sorting it generates the year array

  $('tbody tr').sort(function(a,b){
    var aVal = makeDate(a), bVal = makeDate(b);
    if (aVal < bVal) return -1;
    if (aVal > bVal) return 1;
    return 0;
  }).appendTo('tbody')

  // Create the select from the array of years found in the table

  options.sort().reverse().forEach(function(opt) {
    $select.append($("<option/>",{ text:opt, value:opt}));
  })

  // show / hide the relevant rows based on select value

  $select.on("change",function() {
    $("table tbody tr").hide();
    $("table tbody td:contains("+this.value+")").closest("tr").show();
  }).change();

  
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="year"></select>

<table>
  <tbody>
    <tr>
      <td>06/05/2018</td>
      <td>16:00h</td>
      <td>Chris</td>
    </tr>

    <tr>
      <td>24/10/2019</td>
      <td>20:00h</td>
      <td>Alex</td>
    </tr>

    <tr>
      <td>11/03/2018</td>
      <td>15:00h</td>
      <td>Dani</td>
    </tr>

    <tr>
      <td>07/03/2017</td>
      <td>12:30h</td>
      <td>Fred</td>
    </tr>

    <tr>
      <td>08/04/2019</td>
      <td>12:30h</td>
      <td>Joe</td>
    </tr>


    <tr>
      <td>22/04/2018</td>
      <td>10:30h</td>
      <td>Mike</td>
    </tr>
  </tbody>
</table>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
1

I had a bit of fun with this one, I created a solution using vanilla JavaScript but you could simplify it a bit with jQuery but you don't exactly need jQuery to do this. Here is my solution.

(function(){
  // store a reference to the filter
  let filter = document.getElementById('year');
  // store a reference to the table
  let table = document.getElementById('data-table');
  // array to hold the javascript representation of the rows
  let jRows = [];
  // wire the event handler for the change function
  filter.addEventListener('change', filterRows);

  // initialization function
  function init(){
    // get all the existing rows in the table
    let rows = table.querySelectorAll('tbody>tr');
    // used to store all the availble years
    let years = [];
    // loop over each row
    [...rows].forEach(function(row) { 
      // get the columns in this row
      let cols = row.querySelectorAll('td');
      // create an object to represent the row, break out year and time into their
      // own fields to make it easier to sort later
      var r = {
        date: cols[0].innerHTML,
        year: parseInt(cols[0].innerHTML.substr(cols[0].innerHTML.lastIndexOf('/') + 1)),
        time: cols[1].innerHTML,
        sortTime: parseInt(cols[1].innerHTML.replace('h', '').replace(':', '')),
        name: cols[2].innerHTML
      };
      // store this row in the global array of rows
      jRows.push(r);
      // check if this year is already added to the unique list of years
      if (years.indexOf(r.year) < 0)
        years.push(r.year)
    });

    // sort the years
    years.sort();
    // create the all option for the filter
    let all = document.createElement('option');
    all.value = 'all';
    all.innerHTML = 'All';
    filter.appendChild(all);
    // loop over each year adding the option to the filter
    years.forEach(function(year){
      let opt = document.createElement('option');
      opt.value = year;
      opt.innerHTML = year;
      filter.appendChild(opt);
    });
    // initially call the filterRows function to sort the table
    filterRows();
  }

  function filterRows(){
    // get the current filter
    let selectedFilter = filter.options[filter.selectedIndex].value;
    // clone the rows to manipulate the
    var displayRows = Array.from(jRows);
    // if we aren't showing all the rows, filter them
    if (selectedFilter !== 'all'){
      displayRows = displayRows.filter(r => r.year == selectedFilter)
    }
    // sort the rows by year and time
    displayRows.sort(function (x, y) { return x.year - y.year || x.sortTime - y.sortTime; })
    // create a new tbody element
    var tbody = document.createElement('tbody');
    // loop over each row and construct the tr element
    displayRows.forEach(function(row){
      let r = document.createElement('tr');

      let cDate = document.createElement('td');
      cDate.innerHTML = row.date;

      let cTime = document.createElement('td');
      cTime.innerHTML = row.time

      let cName = document.createElement('td');
      cName.innerHTML = row.name;

      r.appendChild(cDate);
      r.appendChild(cTime);
      r.appendChild(cName);

      tbody.appendChild(r);
    });
    // replace the current tbody with the new one
    table.replaceChild(tbody, table.getElementsByTagName('tbody')[0]);
  }

  // initialize the table
  init();
})();
<select id="year">

</select>

<table id="data-table">
  <tbody>
    <tr>
      <td>06/05/2018</td>
      <td>16:00h</td>
      <td>Chris</td>
    </tr>

    <tr>
      <td>24/10/2019</td>
      <td>20:00h</td>
      <td>Alex</td>
    </tr>

    <tr>
      <td>11/03/2018</td>
      <td>15:00h</td>
      <td>Dani</td>
    </tr>

    <tr>
      <td>08/04/2019</td>
      <td>12:30h</td>
      <td>Joe</td>
    </tr>

    <tr>
      <td>22/04/2018</td>
      <td>10:30h</td>
      <td>Mike</td>
    </tr>
  </tbody>
</table>
Adam H
  • 1,750
  • 1
  • 9
  • 24
1

var select = document.getElementById("year");
var options = ["2018", "2019"];

for (var i = 0; i < options.length; i++) {
  var opt = options[i];
  var el = document.createElement("option");
  el.textContent = opt;
  el.value = opt;
  select.appendChild(el);
}

// get the table.
var table = document.getElementById("table");

// Read data for sorting and filtering
// ---------------------------------------

// iterate through the rows of the table.
var rows = table.getElementsByTagName("tr");
for (var i = 0; i < rows.length; i++) {

  var tr = rows[i];

  // temp vars for filtering/sorting table.
  var year = NaN;
  var month = NaN;
  var day = NaN;
  var hour = NaN;

  // iterate through columns for data/time data.
  var cols = tr.getElementsByTagName("td");
  for (var j = 0; j < cols.length; j++) {

    // get the contents of the cell.
    var td = cols[j];
    var contents = td.innerText;

    // check if contents contains date.
    var dateResult = contents.match(/([0-9]{2})[\/]{1}([0-9]{2})[\/]{1}([0-9]{4})/m);
    // if match, collect year, month, day values.
    if (dateResult != null && 0 < dateResult.length) {

      year = parseInt(dateResult[3]);
      month = parseInt(dateResult[2]);
      day = parseInt(dateResult[1]);

    } else { // only check the time if content is not a "date".

      // check if contents contains time.
      var timeResult = contents.match(/([0-9]{2}):[0-9]{2}h/m);
      // if match, collect hour value.
      if( timeResult != null && 0 < timeResult.length) {
        hour = parseInt(timeResult[1]);
      }

    }

    // break the loop if necessary data has been collected.
    if (!isNaN(year) && !isNaN(month) && !isNaN(day) && !isNaN(hour)) {
      break;
    }

  }

  // create a value for sorting.
  var sort = year * 1000000 + month * 10000 + day * 100 + hour;

  // set sorting and filtering (year) data on row.
  tr.setAttribute('data-sort', sort);
  tr.setAttribute('data-year', year);

}

// Sort the rows by Year/Month/Date/Hour
// ---------------------------------------

// convert rows (NodeList) to Array.
var rowsArray = Array.prototype.slice.call(rows);

// sort the rows array by "sort" value on elments.
rowsArray.sort(function(a, b) {
  return a.dataset.sort - b.dataset.sort;
});

// get the table body.
var tbody = table.getElementsByTagName("tbody")[0];

// reorder rows in table.
for (var i = 0; i < rowsArray.length; i++) {
  
  var row = rowsArray[i];
  
  tbody.removeChild(row);
  tbody.appendChild(row);
  
}

// Add filter event listener to select
// ---------------------------------------

var filterRows = function() {

  // get the selected year.
  var year = parseInt(this.options[this.selectedIndex].value);

  // iterate table rows. show/hide as needed.
  for (var i = 0; i < rows.length; i++) {

    var tr = rows[i];

    if( 0 < year && tr.dataset.year != year ) {
      tr.style.display = "none";
    } else {
      tr.style.display = "table-row";
    }

  }

};

// apply year filter on select change event.
select.addEventListener("change", filterRows);

// optionally call filterRows(); to initialize table sorting.
// filterRows();
<select id="year">
  <!-- added blank option to allow for first year to be selected on load -->
  <option>----</option>
</select>

<table id="table">
  <tbody>
    <tr>
      <td>06/05/2018</td>
      <td>16:00h</td>
      <td>Chris</td>
    </tr>

    <tr>
      <td>24/10/2019</td>
      <td>20:00h</td>
      <td>Alex</td>
    </tr>

    <tr>
      <td>11/03/2018</td>
      <td>15:00h</td>
      <td>Dani</td>
    </tr>

    <tr>
      <td>08/04/2019</td>
      <td>12:30h</td>
      <td>Joe</td>
    </tr>

    <tr>
      <td>22/04/2018</td>
      <td>10:30h</td>
      <td>Mike</td>
    </tr>
  </tbody>
</table>
dzimney
  • 565
  • 1
  • 5
  • 15
  • Nice solution, one small thing is that you aren't taking the minutes of the time into account. For example, if there is a row with 15:07h, another with 15:36 and another with 15:56 the sorting fails. here is an example of what I am talking about: http://jsfiddle.net/2s18ek07/ – Adam H Jan 16 '19 at 17:38
  • @AdamH original post only asked to sort on the hour. – dzimney Jan 16 '19 at 17:54
  • fair enough, in that case, this solution works as intended. – Adam H Jan 16 '19 at 17:59
  • @AdamH I do see what you mean though. OP does appear to consider the full time (hour/minute) to be the "hour". Perhaps a military time thing. – dzimney Jan 16 '19 at 18:25
  • Meh, either way, it's not difficult to modify your solution to take the minutes into account. I'd still call your solution acceptable based on the specs. – Adam H Jan 16 '19 at 18:56
0

Here's how you can start .. you can use several ways to get the year from the td text but while year is the only one has a 4 characters length you can directly use :contains selector

$('#year').on('change' , function(){
   var SelectedYear = $(this).val();
   $('tr').removeClass('inYear');
   $('td:contains("'+ SelectedYear +'")').closest('tr').addClass('inYear');
}).change();  // add .change here will run the change event on load
.inYear{
  background : red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
</head>

<body>
<select id="year">
    <option value="nothing">All Years</option>
    <option value="2018">2018</option>
    <option value="2019">2019</option>
</select>

<table>
  <tbody>   
    <tr>
      <td>06/05/2018</td> 
      <td>16:00h</td> 
      <td>Chris</td>
    </tr>

    <tr>
      <td>24/10/2019</td> 
      <td>20:00h</td> 
      <td>Alex</td>
    </tr>

    <tr>
      <td>11/03/2018</td>
      <td>15:00h</td>
      <td>Dani</td>                     
    </tr>

    <tr>
      <td>08/04/2019</td>
      <td>12:30h</td>
      <td>Joe</td>  
    </tr>

    <tr>
      <td>22/04/2018</td>
      <td>10:30h</td>
      <td>Mike</td>
    </tr>
  </tbody>
</table>            

</body>
</html>

Note: If the select is dynamically generated you'll need to Event binding on dynamically created elements? $(document).on('change' , '#year' , function(){ //code here })

Mohamed-Yousef
  • 23,946
  • 3
  • 19
  • 28
0

If you don't want to use jQuery or other libraries, here's an alternative using plain JS:

https://jsfiddle.net/MtzPwner/2hydzwLk/13/

It leverages the rows property on the table to iterate through rows, and cells property to get the first cell's value. The year is a split and pop from there, which may be replaced with other methods if desired (an indexOf maybe?). Good luck!

Teodor Sandu
  • 1,348
  • 1
  • 20
  • 31