With the help of SO member the.marolie I learned how to implement a JS filter/selector [the 'demo JS filter']. I have this working perfectly on a test page: it shows/hides divs according to "data-types" assigned to them in the body html. However, the selection is made by sliding down a <select>
dropdown list and letting go at the preferred option. That's not quite what I want.
I want to utilise my existing nav-bar dropdown ['my dropdown'] as the filter/selector. I especially want to retain the existing interactivity of my dropdown, whereby one click/tap reveals the whole of the dropdown content block, and one click outside the content block closes it.
I want the elements within my dropdown to represent various show/hide <div>
'options' for the html page, and enable the user to choose from these via an additional click/tap (essentially what the demo JS filter does, but at the instigation of a click/tap). Once revealed via a nav-bar click/tap, the whole dropdown content block has to stay on-screen -as it currently does- for this to be practically possible.
After making my dropdown identifiable via id="media-selector-demo" and name="filter" I was hoping that I could assign the demo JS filter's <option>
elements to the <a>
elements in it, and the whole thing would function like the <select>
dropdown of the demo JS filter. I had a vague idea that using <a>
elements might obviate the need for another onClick
in the JS. I've tried various combinations of <a>
and <option>
elements, but nothing has worked yet.
Do I need another onClick
to invoke the JS filter via my dropdown? or
Can I invoke the JS filter via 'active' <a>
status?
I'm struggling by trial and error.
Here are what I think are the relevant sections of code pertaining to all discussed above:
My dropdown is based on the following code. JS in the page head:
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myDropdownJS() {
document.getElementsByClassName("navbarDROPDOWN-JS")[0].classList.toggle("show");
}
// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var myDropdown = document.getElementsByClassName("navbarDROPDOWN-JS")[0];
if (myDropdown.classList.contains('show')) {
myDropdown.classList.remove('show');
}
}
}
My dropdown html in nav bar (most of the css is just design styling):
<span class="dropdown" onclick="myFunction()">
<a class="dropbtn navbarDROP-ICON" style="opacity:0.5; padding-top:0px;">menu</a>
<a class="dropbtn navbarDROP-TXT" style="opacity:0.5">menu </a>
<a class="dropbtn navbarDROP-TXT">Career Works by Date </a>
<div class="dropdown-content navbarDROPDOWN-JS" >
<a class="tag-bgd-INSTLLN" href="#">Installations (all media)</a>
<a class="tag-bgd-MOVIMG" href="#">Works with moving image (inc. vid/film releases)</a>
<a class="tag-bgd-SNDMUS" href="#">...with sound and music (inc. sound/music releases)</a>
<a class="tag-bgd-PHOTO" href="#">...with photographs</a>
<a class="tag-bgd-DRAW" href="#">...with drawing (inc. 2D works)</a>
<a class="tag-bgd-TXT" href="#">...with text</a>
<a class="tag-bgd-PERF" href="#">...with performative action</a>
<a class="tag-bgd-COLPUB" href="#">Collaborative and public works</a>
<a class="tag-bgd-OBJDEV" href="#">>Objects, garments, devices</a>
<a class="tag-bgd-EDPUB" href="#">Editions, publications</a>
<a class="tag-bgd-CAREER" href="#">Career Works by Date</a>
</div>
Above: the <a href>
elements were going to contain URLs for alternatively styled pages. There is no need for these if I can enable the user to selectively show/hide parts of just this one page, via this dropdown.
The demo JS filter is based on the following code (via SO user the.marolie). JS at page end:
var select = document.getElementById('media-selector-demo');
var filter;
select.addEventListener("change", function() {
filter = select.value;
var elements = document.querySelectorAll('.wk-date_ITEM');
elements.forEach((el) => {
var type = el.dataset.type.split(', ');
if (type.includes(filter)) {
el.classList.remove('hide-by-media');
} else {
el.classList.add('hide-by-media');
}
})
});
Demo JS filter CSS:
.hide-by-media {
display: none;
}
Demo JS filter html in page body:
<select id="media-selector-demo" name="filter">
<option value="INSTLLN"> Installations (all media)</option>
<option value="MOVIMG"> Works with moving image (inc. vid/film releases)</option>
<option value="SNDMUS" >...with sound and music (inc. sound/music releases)</option>
</select>
Example div in page body (there are 80-100 of these):
<!-- ++++++++++ START FULL-WIDTH LIST ENTRY '2017 STATE OF DREAD' ++++++++++ -->
<div id="state-of-dread" class="w3-container wk-date_ITEM" data-type="INSTLLN, SNDMUS">
<div class="w3-container wk-date_TXT-IMG">
<div class="wk-date_GRID">
<div class= "h3 wk-date_DATE"> 2017 </div>
<div class="wk-date_TTL"><h1>State of Dread</h1></div>
<div class="h2 wk-date_KIND-1" >Installation</div>
<div class="p wk-date_KIND-2" ><span class="sound">Sound</span>, for x2 interconnected rooms.<br>AB, CD, EF, Solo exhibition (as trio), Ohrenhoch sound gallery, Berlin.</div>
<div class="wk-date_IMG">
<div class="w3-container w3-right wk-date_IMG-BOX-LSCP">
<img src="../../imgs/INSTALLATION-EVENT/2017_dread_thmb.jpg"
alt="'xx' by Andrew Stones, installation view, xx"></div>
</div>
</div>
</div>
</div>
<!-- ++++++++++ END FULL-WIDTH LIST ENTRY '2017 STATE OF DREAD' ++++++++++ -->
Demo JS filter: JS at end of page:
<script type="text/javascript">
var select = document.getElementById('media-selector-demo');
var filter;
select.addEventListener("change", function() {
filter = select.value;
var elements = document.querySelectorAll('.wk-date_ITEM');
elements.forEach((el) => {
var type = el.dataset.type.split(', ');
if (type.includes(filter)) {
el.classList.remove('hide-by-media');
} else {
el.classList.add('hide-by-media');
}
})
});
</script>
What you would need to do is change the event listener from select, change
to drop down element, click
. you would also need to add the values of the options from the select as data-value attributes on the drop down elements.
1 - add a data-value attribute to the elements to represent what to hide
<a class="tag-bgd-INSTLLN" href="#" data-value="INSTLLN">
2 - target the drop down elements you want to attach the event listener to.
const dropDownElements = document.querySelectorAll('.dropdown-content a')
3 - attach event listeners to the selected targets (PS. the e in the function stands for event, click event listener produces an event object)
dropDownElements.forEach((dropDownElement) => {
dropDownElement.addEventListener('click',(e)=>{
const filter = e.target.dataset.value;
})
})
4 - the rest is just adding the rest of the filter used in the demo js filter
dropDownElements.forEach((dropDownElement) => {
dropDownElement.addEventListener("click", (e) => {
const filter = e.target.dataset.value
var elements = document.querySelectorAll(".wk-date_ITEM")
elements.forEach((el) => {
var type = el.dataset.type.split(", ")
if (type.includes(filter)) {
el.classList.remove("hide-by-media")
} else {
el.classList.add("hide-by-media")
}
})
})
})