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.