Drop Click Content
I noticed some problems with the W3 Schools dropdowns if you use their technique for multiple drop-downs.
- clicking on the head of a drop-down closes that drop-down, but not others.
- if the drop content opens something like a form, you can't click in it without closing the drop-down
Try those operations. The menu-like drop-downs work, but the form closes if you try to click in any of the boxes.
I solved it like this:
Basic Idea:
- enclose the material that you want to stay open if it's clicked in
with
.dropClickContent
instead of.dropContent
- in the window click, check to see if the click is inside a
.dropClickContent
- if so, ignore the click
Also, to allow other headers to close the dropcontent, I switched from
toggleClass
to closeAll
and then addClass
Here's what the HTML looks like for a regular drop-down (that closes on a click):
<li><button class="dropBtn" type="button">Brave</button>
<ul class="dropContent">
<li><button id="btnHarry" type="button">Harry</button></li>
<li><button id="btnRon" type="button">Ron</button></li>
<li><button id="btnHermione" type="button">Hermione</button></li>
</ul>
</li>
Here's the HTML for the drop-down form, which doesn't close on a click. You can close the form by clicking outside it, or on its header:
<li><button class="dropBtn" type="button">Form</button>
<div class="dropClickContent">
<form>
<p><label>What is your name?
<input type="text" name="name"></label></p>
<p><label for="quest">What is your quest?</label></p>
<textarea id="quest" name="quest" rows=5 cols=60></textarea>
<p>
<label>What is your favorite color?
<select name="color">
<option>blue</option>
<option>yellow</option>
</select>
</label></p>
</form>
</div>
</li>
As you can see, the drop-down element is marked with
dropClickContent
instead of dropContent
and the toggles are
dropBtn
.
The JS/JQ code for the drop buttons is like this.
$("nav").on('click', '.dropBtn', function (evt) {
console.log("clicked on "+$(evt.target).text());
var sib = $(evt.target).next().one(); // the next sibling
var shown = sib.hasClass('show'); // whether it's shown
closeAllDropDowns();
// open our dropdown, if not shown
if(!shown) {
sib.addClass('show');
}
});
Notice that this is a delegated handler; a single function on the
nav
element handles all of the .dropBtn
elements. The evt.target
element is the actual button that was clicked. The handler finds the
next sibling of the button, sib
, which is the drop-down
element. The handler then finds out whether the sibling is hidden or
not. The handler closes all drop-downs and then opens this one, if
desired.
Here's how closeAllDropDowns
works:
function closeAllDropDowns() {
console.log("closing all dropdowns");
$(".dropContent,.dropClickContent").removeClass('show');
}
Finally, to allow clicking anywhere outside the dropContent to close any open drop-downs:
// This closes all drop-downs if you
// click anywhere outside the dropContent
// Same effect as W3 Schools, but
// uses jQuery for brevity
// Also checks that we are not
// in a dropClickContent element
$(window).click(function (evt) {
var dcc = $(evt.target).closest(".dropClickContent");
var inDcc = (dcc.length === 1);
if (!evt.target.matches('.dropBtn') &&
!inDcc) {
closeAllDropDowns();
}
});