I have a page that includes a section that's generated from a csv file (in Jekyll, using liquid). In this section, I have individual divs with an image and description. I need to find each div that fits a specific description.
<div class="row">
{% for item in site.data.items %}
<div class="col-md-3 item {{ item.test }} {{ item.industry }} {{ item.shape }}">
<img src="source here">
<br/>
<p>{{ item.name }}</p>
<p>{{ item.description }}</p>
</div>
{% endfor %}
</div>
I assigned classes to each div, and pulled the classes from the csv. This generates a class name of something like "item sticky food pasta".
Now I want to filter the displayed items when a user selects options on the page. I created an array, selectedOptions:
var selectedOptions = [];
Hide the other items:
$(".item").hide();
Push the selected options to the array:
$('input[name="filter-input"]:checked').each(function(i){
selectedOptions.push($(this).val());
});
And loop through the options to display only the items that have the classes selected:
for (var i = 0; i < selectedOptions.length; i ) {
$('.item').each(function() {
if ($(this).hasClass(selectedOptions[i])){
$(this).show();;
}
});
}
This works great, if I wanted every item that has any of the classes. However, what I want is a cumulative effect: I want only the items that have BOTH food AND pasta as a class.
How can I show every item that has all the classes? I know I can use something like $('.classa.classb'), but I'm not sure how to use that with the array I have here.
Thank you!
CodePudding user response:
You can use querySelectorAll to do the dirty work for you in finding all the elmeents that match. Just build up a selector string.
const wrapper = document.querySelector(".wrapper");
document.querySelector("fieldset").addEventListener("change", function () {
const cbs = Array.from(document.querySelectorAll('input[type="checkbox"]:checked'));
const selectedClasses = cbs.map(cb => cb.value).join("");
const matchedElems = wrapper.querySelectorAll(selectedClasses);
console.log(matchedElems);
});
<div class="wrapper">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="one two">1 2</div>
<div class="one three">2 3</div>
<div class="two three">1 3</div>
<div class="one two three">1 2 3</div>
</div>
<form>
<fieldset>
<legend>Filters</legend>
<input type="checkbox" value=".one" id="cb1" /><label for="cb1">1</label>
<input type="checkbox" value=".two" id="cb2" /><label for="cb2">2</label>
<input type="checkbox" value=".three" id="cb3" /><label for="cb3">3</label>
</fieldset>
</form>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
Consider the following.
$(".item").hide();
$('input[name="filter-input"]:checked').each(function(i){
$(".row > .item." $(this).val()).show();
});
This will hide all items and then iterate each of the selected. It will show each of the elements that has the Class selected. The Selector does all the work.
E.G. If the user selects food
and pasta
, all the row
that have food
and pasta
as a child will be shown.
$(".row > .item.pasta").show();
This will be done for each checked item.
You can also bank them up in an Array as you suggested. E.G.:
selectedOptions = ["food", "pasta"];
You can simply use .join()
, yet you may want to add .
to each so it can be a Class selector.
$(".item").hide();
var selectedOptions = [];
$('input[name="filter-input"]:checked').each(function(i){
selectedOptions.push($(this).val());
});
$.each(selectedOptions, function(k, v){
selectedOptions[k] = "." v;
});
$(selectedOptions.join(", ")).show();
This will result in something like:
$(".food, .pasta").show();
You might notice how this is a lot of extra code to accomplish the same thing.