Marjo Posted April 15, 2020 Share Posted April 15, 2020 Hi all! I've been looking at this code snippet that lets you filter div elements based on their class name: https://www.w3schools.com/howto/howto_js_filter_elements.asp I'm wondering how you would go about applying multiple filters to some elements, similar to turning filters on and off, or using boolean operators like AND, OR or NOT. For example (using the dataset used in the link above): assume you want to filter out all the elements that are animals AND whose name is 3 letters long ("cat", "dog" and "cow"). I know it's a silly example, it's just to get my point across. 😅 If you'd make a separate class name for the length of the name, as I understand it you'd still only be able to filter for elements that are animals ("mustang", "cat", "dog", "kiwi" and "cow") OR that have 3 letters ("red", "blue", "cat", "dog" and "cow") - you can't combine both filters. Is there an elegant way to accomplish this that's similar to the code used in the site's example? Or would you have to change your entire approach? (Or is this not possible at all and would you be stuck having to make a separate class name for each and every combination? 😨 That... doesn't sound very practical.) Thanks in advance! Link to comment Share on other sites More sharing options...
Ingolme Posted April 16, 2020 Share Posted April 16, 2020 I'd probably use a different approach. You'll need different code depending on whether you want to choose the intersection of the groups or the union of the groups, or you could have some radio options to choose either an intersection or a union. The general idea is that, when you change any of the options, you will run a function. In this function, you will loop through each of the elements, hide it if it does not meet the criteria, show it otherwise. Instead of using buttons, you will need checkboxes so that you can select more than one of them at a time without having to write too much Javascript. CSS can make the actual checkbox invisible while still styling the clickable label. The result would be something like this: <div class="options"> <label><input type="radio" name="operation" value="union" id="op-union" checked> Union</label> <label><input type="radio" name="operation" value="intersection" id="op-inter"> Intersection</label> </div> <div class="categories"> <span class="category"> <input type="checkbox" value="cars" id="cat-cars"> <label for="cat-cars">Cars</label> </span> <span class="category"> <input type="checkbox" value="animals" id="cat-animals"> <label for="cat-animals">Animals</label> </span> <span class="category"> <input type="checkbox" value="fruits" id="cat-fruits"> <label for="cat-fruits">Fruits</label> </span> <span class="category"> <input type="checkbox" value="colors" id="cat-colors"> <label for="cat-colors">Colors</label> </span> </div> <div class="container"> <div class="filterDiv cars">BMW</div> <div class="filterDiv colors fruits">Orange</div> <div class="filterDiv cars">Volvo</div> <div class="filterDiv colors">Red</div> <div class="filterDiv cars animals">Mustang</div> <div class="filterDiv colors">Blue</div> <div class="filterDiv animals">Cat</div> <div class="filterDiv animals">Dog</div> <div class="filterDiv fruits">Melon</div> <div class="filterDiv fruits animals">Kiwi</div> <div class="filterDiv fruits">Banana</div> <div class="filterDiv fruits">Lemon</div> <div class="filterDiv animals">Cow</div> </div> <script> var checkboxes = document.querySelectorAll(".categories input"); for(var i = 0; i < checkboxes.length; i++) { checkboxes[i].addEventListener("change", filter); } var radios = document.getElementsByName("operation"); for(var i = 0; i < radios.length; i++) { radios[i].addEventListener("change", filter); } filter(); function filter() { var i, j; // Choose an operation var operation = document.getElementById("op-union").checked ? "union" : "intersection"; // Get the selected categories var checkboxes = document.querySelectorAll(".categories input"); var categories = []; var c; for(i = 0; i < checkboxes.length; i++) { if(checkboxes[i].checked) { c = checkboxes[i].value; categories.push(c); } } // Apply the filter var items = document.querySelectorAll(".filterDiv"); var item, show; for(i = 0; i < items.length; i++) { item = items[i]; if(categories.length == 0) { show = true; } else if(operation == "union") { // Union: Only one of the categories needs to exist show = false; for(j = 0; j < categories.length; j++) { if(item.classList.contains(categories[j])) { show = true; break; } } } else { // Intersection: All of the categories must apply show = true; for(j = 0; j < categories.length; j++) { if(!item.classList.contains(categories[j])) { show = false; break; } } } if(show) { item.classList.add("show"); } else { item.classList.remove("show"); } } } </script> Link to comment Share on other sites More sharing options...
dsonesuk Posted April 16, 2020 Share Posted April 16, 2020 You can create a data- attribute to hold 1 or more details related to each item, then its just a matter of filtering the values in data attribute. For instance for your example you could loop through all divfilter classes get textContent length and add to data-details attribute, as data-details="3" which is number of characters, add additional like colours data-details='["3","black"]'; and so on. Link to comment Share on other sites More sharing options...
Marjo Posted April 16, 2020 Author Share Posted April 16, 2020 Thank you both for your input! @Ingolme I tried out your code, but I think I'm overlooking something because it doesn't seem to actually filter anything. It might be something obvious, as I'm very new to JS. Is there still something I'm supposed to add for this code to work (apart from CSS for styling)? Link to comment Share on other sites More sharing options...
Ingolme Posted April 16, 2020 Share Posted April 16, 2020 My code should work as long as you keep the same CSS as before. Without that CSS, it won't hide the elements that should be filtered. Link to comment Share on other sites More sharing options...
Marjo Posted April 16, 2020 Author Share Posted April 16, 2020 1 hour ago, Ingolme said: My code should work as long as you keep the same CSS as before. Without that CSS, it won't hide the elements that should be filtered. *facepalm* Yep, no, you're absolutely right, I accidentally messed up part of the CSS when I tested this earlier 🥴 Works like a charm now, thanks a ton! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now