Reputation: 135
I'm trying to filter results based on data attributes. For the most part I think I'm there (it works on the first 3 selectors), but I get into trouble trying to take the date selector into the equation. At this point I question of my approach is correct altogether - I can change HTML if required - so feel free to provide a better solution.
For the convenience of anyone willing to help here's the fiddle: https://jsfiddle.net/rnbx0c3j/
THANK YOU
Selectors:
<div id="stats_filter">
<div id="stats_filter_wrapper" class="grids">
<div class="grid-3 select-wrapper server first">
<label class="server">Server</label>
<select id="select-server">
<option value="all">All</option>
<option value="NicNicFunGame">NicNicFunGame</option>
<option value="GT3_races">GT3_races</option>
</select>
</div>
<div class="grid-3 select-wrapper track">
<label class="track">Track</label>
<select id="select-track">
<option value="all">All</option>
<option value="ks_brands_hatch">ks_brands_hatch</option>
<option value="Imola">Imola</option>
<option value="Spa">Spa</option>
</select>
</div>
<div class="grid-3 select-wrapper car">
<label class="car">Car</label>
<select id="select-car">
<option value="all">All</option>
<option value="ariel_atom_v8">ariel_atom_v8</option>
<option value="rr_caterham_academy_620r">rr_caterham_academy_620r</option>
<option value="ks_porsche_911_gt1">ks_porsche_911_gt1</option>
</select>
</div>
<div class="grid-3 select-wrapper date">
<label class="date">Date</label>
<select id="select-date">
<option value="all">All</option>
<option value="7">Last 7 days</option>
<option value="30">Last 30 days</option>
<option value="182">Last 6 months</option>
<option value="365">Last 12 months</option>
</select>
</div>
</div>
</div>
HTML to be filtered
<div class="stats-section" id="sectionID_1" data-server="NicNicFunGame" data-track="ks_brands_hatch" data-date="27/09/2019" data-car="ariel_atom_v8">sectionID_1</div>
<div class="stats-section" id="sectionID_2" data-server="NicNicFunGame" data-track="Imola" data-date="03/07/2019" data-car="rr_caterham_academy_620r">sectionID_2</div>
<div class="stats-section" id="sectionID_3" data-server="GT3_races" data-track="Spa" data-date="14/01/2019" data-car="ariel_atom_v8, ks_porsche_911_gt1">sectionID_3</div>
JS
var $select = $('#stats_filter select');
var $statsSection = $('.stats-section');
$select.change(function () {
var include = '';
var exclude = [];
var showAll = true;
var filterDate = false;
$select.each(function () {
var val = $(this).children(':selected').val();
if (val !== 'all') {
switch ($(this).prop('id')) {
case 'select-server':
include += "[data-server='" + val + "']";
break;
case 'select-track':
include += "[data-track='" + val + "']";
break;
case 'select-car':
include += "[data-car*='" + val + "']";
break;
case 'select-date':
var selectedDate = new Date(new Date().setDate(new Date().getDate() - val));
var dd = selectedDate.getDate();
var mm = selectedDate.getMonth() + 1;
var yyyy = selectedDate.getFullYear();
if (dd < 10) {
dd = '0' + dd;
}
if (mm < 10) {
mm = '0' + mm;
}
selectedDate = dd + '/' + mm + '/' + yyyy;
//exclude when date is out of range
$statsSection.each(function () {
var sectionDate = $(this).data('date');
if (process(sectionDate) < process(selectedDate)) {
exclude.push("[data-date='" + sectionDate + "']");
}
exclude.join(',');
});
function process(date) {
var parts = date.split("/");
return new Date(parts[2], parts[1] - 1, parts[0]);
}
filterDate = true;
break;
}
showAll = false;
}
});
if (showAll) {
$statsSection.show();
} else {
//HOW TO DEAL WITH THE DATES??
if (filterDate == true) {
alert('the following dates should be excluded from the results: ' + exclude);
}
//this works for the non-date selectors
$statsSection.not($(include)).hide();
$statsSection.filter($(include)).show();
}
});
Upvotes: 2
Views: 1168
Reputation: 2232
You can store all of your stats-section
into array of objects and search with array filter
var t0 = performance.now();
var initialized = false;
var $select = $('#stats_filter select');
function initialize() {
mySelectors = [];
$statsSection = $('.stats-section');
console.log("First search will be costly");
$($statsSection).each(function (i, e) {
let temp = $(e).data();
temp.element = $(e);
let myDate = temp.date.split("/");
temp.date = new Date(myDate[1] + "/" + myDate[0] + "/" + myDate[2]).getTime();//fix date format and convert to timestamp
mySelectors.push(temp);
});
initialized = true;
}
$select.change(function () {
var t0 = performance.now();
if (!initialized)
initialize();
var result = mySelectors;
$select.each(function () {
var val = $(this).val(); //you don't need to search the selected child
if (val !== 'all') {
switch ($(this).prop('id')) {
case 'select-server':
result = result.filter(obj => {
return obj.server === val;
});
break;
case 'select-track':
result = result.filter(obj => {
return obj.track === val;
});
break;
case 'select-car':
result = result.filter(obj => {
return obj.car === val;
});
break;
case 'select-date':
var selectedDate = new Date(new Date().setDate(new Date().getDate() - val)).getTime(); // timestamp
result = result.filter(obj => {
return obj.date > selectedDate;
});
}
}
});
$($statsSection).hide();
$.each(result, function (i, e) {
$(e.element).show();
});
var t1 = performance.now();
console.log("Search performance " + (t1 - t0) + " milliseconds.");
});
var t1 = performance.now();
console.log("Initialize performance " + (t1 - t0) + " milliseconds.");
.grids { clear: both;max-width: 1920px;margin: 0;}
#stats_filter_wrapper .select-wrapper { width: 25%; float:left; }
#stats_filter_wrapper .select-wrapper label { overflow: hidden; font-weight: 700; }
#stats_filter_wrapper .select-wrapper select { display: block; font-size: 16px; color: #6a6d73; line-height: 1.3; padding: 8px 25px 5px 8px; width: 100%; max-width: 100%; box-sizing: border-box; margin: 0; }
.stats-section{padding:20px 0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="stats_filter">
<div id="stats_filter_wrapper" class="grids">
<div class="grid-3 select-wrapper server first">
<label class="server">Server</label>
<select id="select-server">
<option value="all">All</option>
<option value="NicNicFunGame">NicNicFunGame</option>
<option value="GT3_races">GT3_races</option>
</select>
</div>
<div class="grid-3 select-wrapper track">
<label class="track">Track</label>
<select id="select-track">
<option value="all">All</option>
<option value="ks_brands_hatch">ks_brands_hatch</option>
<option value="Imola">Imola</option>
<option value="Spa">Spa</option>
</select>
</div>
<div class="grid-3 select-wrapper car">
<label class="car">Car</label>
<select id="select-car">
<option value="all">All</option>
<option value="ariel_atom_v8">ariel_atom_v8</option>
<option value="rr_caterham_academy_620r">rr_caterham_academy_620r</option>
<option value="ks_porsche_911_gt1">ks_porsche_911_gt1</option>
</select>
</div>
<div class="grid-3 select-wrapper date">
<label class="date">Date</label>
<select id="select-date">
<option value="all">All</option>
<option value="7">Last 7 days</option>
<option value="30">Last 30 days</option>
<option value="182">Last 6 months</option>
<option value="365">Last 12 months</option>
</select>
</div>
</div>
</div>
<div class="stats-section" id="sectionID_1" data-server="NicNicFunGame" data-track="ks_brands_hatch" data-date="27/09/2019" data-car="ariel_atom_v8">sectionID_1</div>
<div class="stats-section" id="sectionID_2" data-server="NicNicFunGame" data-track="Imola" data-date="03/07/2019" data-car="rr_caterham_academy_620r">sectionID_2</div>
<div class="stats-section" id="sectionID_3" data-server="GT3_races" data-track="Spa" data-date="14/01/2019" data-car="ariel_atom_v8, ks_porsche_911_gt1">sectionID_3</div>
Upvotes: 1
Reputation: 9525
So, for the non-date items your technique is to compute the jquery selector for elements that should be included, then apply that to the data divs.
Quite a nice approach in that you are constructing multiple jquery filters as you build up the 'include' variable.
The difficulty in applying the same technique for the dates is that this produces a range test which is hard to put into a jquery selector. My solution is to construct an array of qualifying data-date values and carry out a second filter in the final step.
The changes are:
Step 1. Define a new variable:
var dateInclude = [];
Step 2. In the section where you determine if the date is valid push the valid values into the dataInclude filters array
//exclude when date is out of range
$statsSection.each(function () {
var sectionDate = $(this).data('date');
if (process(sectionDate) > process(selectedDate)) {
dateInclude.push("[data-date='" + sectionDate + "']");
}
});
Step 3: In the output section we now combine the dateInclude as a second filter. Note that your initial filters operate as boolean AND, but the date filters have to operate as boolean OR's. Therefore the dateInclude filter is applied in the show() operation as a second step.
$statsSection.hide();
include = (dateInclude.length > 0 && include === '' ? '*' : include);
dateInclude = (dateInclude.length === 0 ? ['*'] : dateInclude );
$('#info').html(include + ' :: ' + dateInclude.join());
$statsSection.filter(include).filter(dateInclude.join()).show();
The first line (below) hides all the data divs pre-emptively.
$statsSection.hide();
The next lines (below) operate on the filters to ensure that they both have a value. If no date filters are present we inject a match-all, and same for the 'include' filters for the other select boxes.
include = (dateInclude.length > 0 && include === '' ? '*' : include);
dateInclude = (dateInclude.length === 0 ? ['*'] : dateInclude );
Finally we bring this together as below.
$statsSection.filter(include).filter(dateInclude.join()).show();
To help visualise it I added some output to the fiddle
For example, selecting server=NicNicFunGame and date=last six months produces filters:
$statsSection.filter("[data-server='NicNicFunGame']").filter("[data-date='27/09/2019'],[data-date='03/07/2019']").show();
See my working fiddle at https://jsfiddle.net/JamesE442/qktfbp15/38/
Upvotes: 2