I am creating a set of filters and once they are selected, corresponding divs should show based on ALL of the attributes being selected.
I can get this to work one at a time, but my issue is when trying to get them to work together. I feel like there is probably a better approach to this in general?
Here are my select menus:
<div class="filters">
<select class="filter-location">
<option value="" disabled="" selected="">Location</option>
<option data-location="Remote">Remote – United States</option>
<option data-location="Portland, OR">Portland, OR</option>
<option data-location="Seattle, WA">Seattle, WA</option>
</select>
<select class="filter-team">
<option value="" disabled="" selected="">Team</option>
<option data-team="Sales">Sales</option>
<option data-team="Support">Support</option>
<option data-team="Management">Management</option>
</select>
<select class="filter-type">
<option value="" disabled="" selected="">Type</option>
<option data-type="Full-Time">Full-Time</option>
<option data-type="Contract">Contract</option>
</select>
</div>
Here is a simplified version of my HTML markup:
<div class="job" data-team="Sales" data-location="Remote" data-type="Full-Time">
<p>Job Content Here</p>
</div>
<div class="job" data-team="Management" data-location="Portland, OR" data-type="Contract">
<p>Job Content Here</p>
</div>
<div class="job" data-team="Sales" data-location="Seattle, WA" data-type="Full-Time">
<p>Job Content Here</p>
</div>
Here is my jQuery that works for showing one filter at a time:
<script type="text/javascript">
jQuery(document).ready(function($) {
$('.filters select').on('change', function() {
var location_value = $(':selected', this).data('location');
var team_value = $(':selected', this).data('team');
var type_value = $(':selected', this).data('type');
$('.job').hide();
$(".job").each(function( index ) {
if ($(this).data('location') == location_value) {
$(this).show();
}
if ($(this).data('team') == team_value) {
$(this).show();
}
if ($(this).data('work_type') == type_value) {
$(this).show();
}
});
});
});
</script>
Following creates an array of filter objects for each <select>
that has a value that looks like:
[
{
"filter": "location",
"value": "Remote"
},
{
"filter": "team",
"value": "Sales"
}
]
It then uses Array#every() to make sure that each filter matches a job's data-
attributes to determine whether to show it or not.
Note I made the <select>
elements a bit more generic and added a data-filter
attribute to each one and just used value
on the <option>
elements
const $sels = $('.filters select'),
$jobs = $('.job')
$sels.change(function(){
const filters = $sels.filter(function(){
return !!this.value
}).map(function(){
return {filter: $(this).data('filter'), value : this.value}
}).get();
//console.log('Filters', filters)
// hide all jobs then filter the ones to show
const $filterJobs = $jobs.hide().filter(function(){
const data = $(this).data()
return filters.every(function(obj){
return data[obj.filter] === obj.value
});
}).show();
// toggle "no-match" depending on length of filter jobs collection
$('#no-match').toggle( !$filterJobs.length )
});
.job, #no-match {
display: none
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="filters">
<select data-filter="location">
<option value="">Location</option>
<option value="Remote">Remote – United States</option>
<option value="Portland, OR">Portland, OR</option>
<option value="Seattle, WA">Seattle, WA</option>
</select>
<select data-filter="team">
<option value="">Team</option>
<option value="Sales">Sales</option>
<option value="Support">Support</option>
<option value="Management">Management</option>
</select>
<select data-filter="type">
<option value="">Type</option>
<option value="Full-Time">Full-Time</option>
<option value="Contract">Contract</option>
</select>
</div>
<div id="no-match">
<h3>No Match</h3>
</div>
<div class="job" data-team="Sales" data-location="Remote" data-type="Full-Time">
<p>Sales Remote Full Time</p>
</div>
<div class="job" data-team="Management" data-location="Portland, OR" data-type="Contract">
<p>Management Portland Contract</p>
</div>
<div class="job" data-team="Sales" data-location="Seattle, WA" data-type="Full-Time">
<p>Sales Seattle Full Time</p>
</div>