Reputation: 2170
I have posted about this already, but I think my question was poorly explained. I have multiple divs with class of "popupEdit".
I want to be able to target these using getElementsByClassName.....the result being a popup with some input field. See the code below.
I know that getElementsByClassName returns an array of all the elements with the class EditQuestion, but I have failed to write a function that works to use this array. My lack of skill (I'm a newbie).
Could someone give me the solution so I have something I can study. Apologies for asking directly for the answer...I have tried numerous things without success.
Many thanks
HTML
<button class="EditQuestion">Edit</button>
<div class="overlay2"></div>
<div class="popupEdit">
<h2>Edit Question, some input box here..</h2>
<button class="CloseBtn2">Close</button>
</div>
JS
window.onload = function () {
document.getElementsByClassName("EditQuestion").onclick = function () {
var overlay2 = document.getElementsByClassName("overlay2");
var popupEdit = document.getElementsByClassName("popupEdit");
overlay2.style.display = "block";
popupEdit.style.display = "block";
};
document.getElementsByClassName("CloseBtn2").onclick = function () {
var overlay2 = document.getElementsByClassName("overlay2");
var popupEdit = document.getElementsByClassName("popupEdit");
overlay2.style.display = "none";
popupEdit.style.display = "none";
};
};
CSS
button.EditQuestion{
padding: 0;
border: none;
background: none;
color:#A8A8A8;
font-weight: bold;
}
button.CloseBtn2 {
padding: 0;
border: none;
background: none;
position:absolute;
right:10px;
top:5px;
}
.popupEdit {
display:none;
position:fixed;
left:40%;
top:30%;
width:600px;
height:150px;
margin-top:-75px;
margin-left:-150px;
background:#FFFFFF;
border:1px solid #000;
z-index:100000;
}
.overlay2 {
display:none;
position:fixed;
left:0px;
top:0px;
width:100%;
height:100%;
background:#000;
opacity:0.5;
z-index:99999;
}
Edited version - I have tried to use querySelectorAll as suggested by TJ Crowder....the querySelector works, but when I add in the for loop and change to querySelectorAll it fails....any suggestions
window.onload = function () {
document.querySelectorAll(".EditQuestion").onclick = function () {
var overlay2 = document.querySelectorAll(".overlay2");
var popupEdit = document.querySelectorAll(".popupEdit");
var index;
for (index = 0; index < overlay2.length; ++index) {
overlay2[index].style.display = "none";
popupEdit[index].style.display = "block";
}
};
document.querySelectorAll(".CloseBtn2").onclick = function () {
var overlay2 = document.querySelectorAll(".overlay2");
var popupEdit = document.querySelectorAll(".popupEdit");
var index;
for (index = 0; index < overlay2.length; ++index) {
overlay2[index].style.display = "none";
popupEdit[index].style.display = "block";
}
};
};
Upvotes: 0
Views: 3441
Reputation: 1074148
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"));
});
Upvotes: 3
Reputation:
Below is a sample working code for you to get started — http://jsfiddle.net/vVq7E/1.
Also learn to use the following getElementsByClassName
, addEventListener
, nextElementSibling
, element.style
which are used in this code
<div class='modules'>
<button class='edit'>Edit</button>
<div class='overlay'>
<p>Hello!</p>
<button class='close'>Close</button>
</div>
</div>
...
window.onload = function init() {
modules = document.getElementsByClassName('modules');
len = modules.length;
var i = 0;
for (; i < len; i++) {
modules[i].getElementsByClassName('edit')[0].addEventListener('click', showOverlay);
modules[i].getElementsByClassName('close')[0].addEventListener('click', hideOverlay);
}
}
function showOverlay() {
this.nextElementSibling.style.display = 'block';
}
function hideOverlay() {
var overlays = document.getElementsByClassName('overlay');
for (var i = 0; i < len; i++) {
if (overlays[i].style.display === 'block') {
overlays[i].style.display = 'none';
return;
}
}
.modules {
/*optional!*/
margin:10px;
}
.overlay {
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
display:none;
/*optional!*/
padding:20px;
/*optional!*/
background:yellow;
}
Upvotes: 0
Reputation: 3765
getElementsByClassName
returns NodeList or HTMLCollection.
document.getElementsByClassName("EditQuestion")[0].onclick = function () { //<-- get the first (and only?) element from the list
Upvotes: 1
Reputation: 1422
If you want to use getElementsByClassName
to get the ,Array of all element with that class then :
It is something like below:
var els = document.getElementsByClassName("myclass");
Array.prototype.forEach.call(els, function(el) {
// Do stuff with the element
console.log(el.tagName);
});
// Or optionally
[].forEach.call(els, function () {...});
Answered by Tim Down on getElementsByClassName
Upvotes: 0