getElementsByClassName
(on the browsers where it exists) returns a list, not a single element. So this line and similar:
overlay2.style.display = "none";
...fails, because the list doesn't have a style
property.
If you just want to handle the first match, you can grab it via [0]
:
overlay2[0].style.display = "none";
(That will fail if there are no matches, though.) Or, since getElementsByClassName
isn't as well-supported as querySelector
, you might prefer:
overlay2 = document.querySelector(".overlay2"); // Gives you the first match; note the dot
overlay2.style.display = "none";
Or if you want to loop through all of them, you need a loop:
var index;
for (index = 0; index < overlay2.length; ++index) {
overlay2[index].style.display = "none";
}
To get the list for that loop, either use getElementsByClassName
as you are currently (but it won't work on IE8), or use querySelectorAll
(which will):
overlay2 = document.querySelectorAll(".overlay2"); // Gives you a list
Could you show me how you would incorporate this loop into the JS function.
I don't think you want a loop; you just want to handle the specific overlay and popup related to the button, right?
I'd probably change the HTML slightly so that each group has a group div or similar around it:
<div class="question"><!-- Wrapper div for each question -->
<button class="EditQuestion">Edit</button>
<div class="overlay2" style="display: none"></div><!-- Note I've hidden ... -->
<div class="popupEdit" style="display: none"> <!-- ...these by default -->
<h2>Edit Question, some input box here..</h2>
<button class="CloseBtn2">Close</button>
</div>
</div>
...and use event delegation:
var container = document.getElementById("questions");
hookEvent(container, "click", function(event) {
var button, group, overlay, display;
// Find the button that was clicked, if any
button = event.target;
while (button && (
button.tagName.toUpperCase() !== "BUTTON" ||
!button.className.match(/\bEditQuestion\b|\bCloseBtn2\b/)
)) {
button = button.parentNode;
}
if (button) {
// One of our desired buttons was clicked, find the parent
group = button.parentNode;
while (group && !group.className.match(/\bquestion\b/)) {
group = group.parentNode;
}
if (group) {
overlay = group.querySelector(".overlay2");
display = overlay.style.display === "block" ? "none" : "block";
overlay.style.display = display;
group.querySelector(".popupEdit").style.display = display;
}
}
});
...where hookEvent
looks something like this:
function hookEvent(element, eventName, handler) {
if (element.addEventListener) {
element.addEventListener(eventName, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + eventName, function(event) {
var e = event || window.event;
if (!e.target) {
e.target = e.srcElement;
}
handler.call(element, e);
});
} else {
throw "addEventListener or attachEvent required";
}
}
The great thing about event delegation is that since you're handling the event on a container, it doesn't matter how much you add or remove questions in the container, it just keeps working.
A lot of the code above is to deal with IE weirdness, and to handle the event delegation. FWIW, a good DOM library can make that all a LOT simpler for you. Here's a jQuery example:
$("selector for the container").on("click", ".EditButton, .CloseBtn2", function() {
var button = $(this);
button.closest('.question').find(".overlay2, .popupEdit").toggle(button.is(".EditButton"));
});