I have an html page consisting of 80-100 css-styled divs each containing a grid with an image and information about a single artwork. (Each div already has a unique Id, to enable linking-in to a specific place in the page.)
Many of the works employ several media, and I want the user to be able to make visible only artworks that use particular media.
In other words, I want to make the html page behave like a filterable database, where a single drop-down menu acts like a list of filters, and clicking on the "artworks using video" option (for e.g.) hides all works that do not use video.
I'm want to achieve the above with css and Javascript only.
As I understand it:
I can make my artwork divs selectable by assigning different classes, such as ".med-drawing" ".med-video" ".med-sound" etc. There would need to be 10-12 of these classes.
Then, I'd need a way, onClick, to "make visible all the divs that do have" a particular class, AND "make invisible the divs that do not have" that class. This, for each of 10 - 12 different classes.
I've been trying a series of Javascript "onClick + GetElementsByClass + [some visibility control]" functions assigned to different elements in a menu. I have limited javascript coding knowledge and so far I can't get anything to work.
What I really need is a bare-essentials javascript/css solution that I can modify to suit my project.
I'd be grateful for any help.
EDIT- 1 day later (code added below these paras):
With the help of the.marolie I now have a basic 'filter/selector' working on a test page. It can select and show/hide divs precisely as I wanted, although utilising "data-type" rather than class.
Thanks!
EDIT 2
I had added more to this post, but, on reflection, realised that my initial question had been perfectly answered by the.marolie. My follow-up material really constututed a different question, so I've removed it here and bumped it to a new post: Using only JS and css: can I implement a filter, so that: clicking/tapping within a JS dropdown menu shows/hides page divs according to data-type?
To get you started, one approach would be:
Add common class name and a data
attribute to each div based on the type of content. For eg:
<div class="grid-item" data-type="text">
<span>Text</span>
</div>
<div class="grid-item" data-type="audio">
<span>Audio</span>
</div>
Once you have this, you can add a select box which will contain option with values that are same as the data-type
. Like:
<select id="cstm-select" name="filter">
<option value="text">Text</option>
<option value="image">Image</option>
<option value="audio">Audio</option>
<option value="video">Video</option>
</select>
If you see the above code, the value
of option contain the different data-type
attribute values that we will be using to filter the content.
Now for the js logic, first we need to listen to the onChange
event of our select
element, store the selected value in a variable and then query the elements once the use selects an option using the document.querySelectorAll()
function and pass the common class name as the function parameter so that only the elements that we need to filter will be selected.
Once queried, we can loop through each element using forEach
, then check if the data-type
attribute of each element against the selected filter value and if it doesn't match, add a class name to the element which will control the visibility of the element.
Also, we need to make sure that if the data-type
matches, we remove the class name so that the element is visible when the user selects a different filter.
Combining this, here is a small fiddle. Modify the code as required for your project.
var select = document.getElementById('cstm-select');
var filter;
select.addEventListener("change", function() {
filter = select.value;
var elements = document.querySelectorAll('.grid-item');
elements.forEach((el) => {
var type = el.dataset.type.split(' ');
if (type.includes(filter)) {
el.classList.remove('hidden');
} else {
el.classList.add('hidden');
}
})
});
.hidden {
display: none;
}
<select id="cstm-select" name="filter">
<option value="text">Text</option>
<option value="image">Image</option>
<option value="audio">Audio</option>
<option value="video">Video</option>
</select>
<div class="grid-container">
<div class="grid-item" data-type="text">
<span>Text</span>
</div>
<div class="grid-item" data-type="audio video">
<span>Audio / Video</span>
</div>
<div class="grid-item" data-type="video">
<span>Video</span>
</div>
<div class="grid-item" data-type="audio">
<span>Audio</span>
</div>
<div class="grid-item" data-type="image">
<span>Image</span>
</div>
<div class="grid-item" data-type="text">
<span>Text</span>
</div>
<div class="grid-item" data-type="text">
<span>Text</span>
</div>
</div>
Edit: As per your comment, I have modified the code to include filter functionality if there are multiple data-type
defined for a single grid-item
.
The logic change here is that, we define the multiple data-type
like this - data-type="audio video"
. Provide a space between each items or you can use a comma separator as well.
And in the js code, we first split the data-type
using str.split()
function which stores the values in an array like ['audio', 'video']
.
Now that we have this, all we need to do is check if the selected filter is included in the dataset array and apply or remove the class as required. Check the modified jsfiddle.
Note: Whatever separator we use in data-type
attribute, we need to define the same separator in the js code while we split.
If we use comma, the in js, it would be:
var type = el.dataset.type.split(',');