I have timeline with a filter that allows users to show/hide events. The way the CSS is formatted requires that the entire parent (“.timeline”) be hidden if no matches were made in the filter, otherwise there’s a border that remains visible:
<form>
<p>Topics</p>
<input type="checkbox" name="topic" value="topic1" id="topic1"><label for="topic1">Topic 1</label>
<input type="checkbox" name="topic" value="topic2" id="topic2"><label for="topic2">Topic 2</label>
<input type="checkbox" name="topic" value="topic3" id="topic3"><label for="topic3">Topic 3</label>
</form>
<form>
<p>
Format
</p>
<input type="checkbox" name="format" value="format1" id="format1"><label for="format1">Format 1</label>
<input type="checkbox" name="format" value="format2" id="format2"><label for="format2">Format 2</label>
</form>
<br>
<div class="timeline">
<div class="event" data-id="event1"
data-category="topic1 format1">
Date & Time<br>
Content
</div>
<div class="event" data-id="event2"
data-category="topic2 format2">
Date & Time<br>
Content
</div>
</div>
var $filterCheckboxes = $('input[type="checkbox"]');
$filterCheckboxes.on('change', function () {
var selectedFilters = {};
$filterCheckboxes.filter(':checked').each(function () {
if (!selectedFilters.hasOwnProperty(this.name)) {
selectedFilters[this.name] = [];
}
selectedFilters[this.name].push(this.value);
});
var $filteredResults = $('.event');
$.each(selectedFilters, function (name, filterValues) {
$filteredResults = $filteredResults.filter(function () {
var matched = false,
currentFilterValues = $(this).data('category').split(' ');
$.each(currentFilterValues, function (_, currentFilterValue) {
if ($.inArray(currentFilterValue, filterValues) != -1) {
matched = true;
return false;
}
});
return matched;
});
});
$('.event').hide().filter($filteredResults).show();
});
I tried including $('.timeline').hide().filter($filteredResults).show();
to the last line, which works at first, but then when you uncheck boxes none of the elements reappear.
Is there some sort of if/then statement I should be using? Like, if matched = false { document.getElementsByClassName("timeline").style.display = "none"; };
Advertisement
Answer
This is the Javascript you need
var $filterCheckboxes = $('input[type="checkbox"]');
$filterCheckboxes.on('change', function () {
$('.timeline').show();
var selectedFilters = {};
$filterCheckboxes.filter(':checked').each(function () {
if (!selectedFilters.hasOwnProperty(this.name)) {
selectedFilters[this.name] = [];
}
selectedFilters[this.name].push(this.value);
});
var $filteredResults = $('.event');
$.each(selectedFilters, function (name, filterValues) {
$filteredResults = $filteredResults.filter(function () {
var matched = false,
currentFilterValues = $(this).data('category').split(' ');
$.each(currentFilterValues, function (_, currentFilterValue) {
if ($.inArray(currentFilterValue, filterValues) != -1) {
matched = true;
return false;
}
});
return matched;
});
});
$('.event').hide().filter($filteredResults).show();
var all_hidden = true;
$('.event').each(function (index) {
if ($(this).is(":visible")) {
all_hidden = false;
}
});
if (all_hidden) {
$('.timeline').hide();
}
});
I added an if statement at the end to check if all events are hidden, by looping through all events and checking their visibility with if ($(this).is(":visible"))
. If they are all hidden it hides the timeline, if not the timeline stays put.
At the start of your function I added a line to make sure the timeline is visible before starting the visibility loop or else all events will be hidden and the code won’t work as $(this).is(":visible")
will always return false.