I'm working on Cole Steele's Web Developer Bootcamp on Udemy #264. Event Bubbling. I'm trying to build a function which will allow one or more objects to be passed in and to execute the same action (toggle the classList 'hide' so that the 'Click Here to Hide' button goes away and the 'Click Here to Show' button appears) on each of them.
I am able to get this working by calling the function separately, such as
const container = document.querySelector('#container')
const show = document.querySelector('#show')
function hideOneElement(ele){
ele.classList.toggle('hide');
}
show.addEventListener('click', function () {
hideOneElement(container);
hideOneElement(show);
})
However, when I try to call the function with both container (the div that says 'Click here to hide') and show at the same time, I can't get it to work. I tried writing the hide function as a for...of, such as
function hideElements(elements){
for (const ele of elements) {
ele.classList.toggle('hide')
}
}
let stuffToHide = [container,show]
hideElements(stuffToHide)
However this does not seem to work. I also tried passing in as two separate arguments but that also doesn't seem to work:
function hideElements(ele1, ele2) {
ele1.classList.toggle('hide');
ele2.classList.toggle('hide')
}
hideElements(container, show);
At this point, I'm not sure where to go, and my Google-jitsu is not finding anything useful. This isn't really part of the course exercise, but seems like I'm fundamentally missing something about calling functions.
Full code and HTML below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.hide {
display: none;
}
</style>
</head>
<body>
<section onclick="alert('sectopm clicked')">
<p onclick="alert('paragraph clicked')">I am a paragraph
<button onclick="alert('button clicked')">Click</button>
</p>
</section>
<div id="container">
Click to Hide
<button id="colorbtn">Change Color</button>
</div>
<div id="show">
Click here to Show
</div>
<script src="app.js"></script>
</body>
</html>
const makeRandColor = () => {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
return (`rgb(${r},${g},${b})`);
}
const button = document.querySelector('#colorbtn')
const container = document.querySelector('#container')
const show = document.querySelector('#show')
function hideElements(ele1, ele2) {
// for (const ele of elements) {
// ele.classList.toggle('hide')
// }
// elements.classList.toggle('hide')
ele1.classList.toggle('hide');
ele2.classList.toggle('hide')
}
function hideOneElement(ele){
ele.classList.toggle('hide');
}
//hideElements(show); //run function once to toggle on the 'hide' class so that this is not shown by default.
hideElements(show)
button.addEventListener('click', function (e) {
container.style.backgroundColor = makeRandColor();
e.stopPropagation();
})
container.addEventListener('click', function () {
hideElements(container, show);
//hideElements(container, show); //hide the 'click here to hide' stuff
})
show.addEventListener('click', function () {
hideElements(container);
hideElements(show);
})
show.addEventListener('click', function () {
hideOneElement(container);
hideOneElement(show);
})
CodePudding user response:
Some blocks will not work for sure - as you call hideElements with a single argument - the second arg will be undefined and there's no classList on undefined of course (causes error).
And also it's very confusing because you add event listener on the show element twice..
Copied from your post and added comments:
//hideElements(show); //run function once to toggle on the 'hide' class so that this is not shown by default.
hideElements(show) // - this will error like I said above as elem2 will be undefined..
button.addEventListener('click', function (e) {
container.style.backgroundColor = makeRandColor();
e.stopPropagation();
})
container.addEventListener('click', function () {
hideElements(container, show);
//hideElements(container, show); //hide the 'click here to hide' stuff
})
//below you make same event listener twice which is very confusing :
show.addEventListener('click', function () {
hideElements(container);
hideElements(show);
})
show.addEventListener('click', function () {
hideOneElement(container);
hideOneElement(show);
})
CodePudding user response:
"I'm trying to build a function which will allow one or more objects to be passed in" so you need to be able to call hideElements as either hideElements(ele1) or hideElements(ele1, ele2)?
If that's the case you'll need to pass an array vs individual variables. You were on the right track with the commented out code here:
// for (const ele of elements) {
// ele.classList.toggle('hide')
// }
// elements.classList.toggle('hide')
But you weren't trying to pass them as an array and you can't loop through an individual element (there's only one). If you wrap your variables in an array using [] that should fix your issues.
Example:
function hideElements(elements) {
for (const ele of elements) {
ele.classList.toggle('hide')
}
}
hideElements([show]); //run function once to toggle on the 'hide' class so that this is not shown by default.
container.addEventListener('click', function() {
hideElements([container, show]);
})
show.addEventListener('click', function() {
hideElements([container, show]);
})
Working Example:
const makeRandColor = () => {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
return (`rgb(${r},${g},${b})`);
}
const button = document.querySelector('#colorbtn')
const container = document.querySelector('#container')
const show = document.querySelector('#show')
function hideElements(elements) {
for (const ele of elements) {
ele.classList.toggle('hide')
}
}
function hideOneElement(ele) {
ele.classList.toggle('hide');
}
hideElements([show]); //run function once to toggle on the 'hide' class so that this is not shown by default.
button.addEventListener('click', function(e) {
container.style.backgroundColor = makeRandColor();
e.stopPropagation();
})
container.addEventListener('click', function() {
hideElements([container, show]);
})
show.addEventListener('click', function() {
hideElements([container, show]);
})
.hide {
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<section onclick="alert('sectopm clicked')">
<p onclick="alert('paragraph clicked')">I am a paragraph
<button onclick="alert('button clicked')">Click</button>
</p>
</section>
<div id="container">
Click to Hide
<button id="colorbtn">Change Color</button>
</div>
<div id="show">
Click here to Show
</div>
<script src="app.js"></script>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>