<!DOCTYPE html>
<html>
<body>
<h2>What Can JavaScript Do?</h2>
<p>JavaScript can change HTML attribute values.</p>
<p>In this case JavaScript changes the value of the src (source) attribute of an image.</p>
<button onclick="document.getElementById('bulb0').src='pic_bulbon.gif'">Turn on the light</button>
<img id="bulb0" src="pic_bulboff.gif" style="width:50px">
<button onclick="document.getElementById('bulb0').src='pic_bulboff.gif'">Turn off the light</button>
<p></p>
<button onclick="document.getElementById('bulb1').src='pic_bulbon.gif'">Turn on the light</button>
<img id="bulb1" src="pic_bulboff.gif" style="width:50px">
<button onclick="document.getElementById('bulb1').src='pic_bulboff.gif'">Turn off the light</button>
<p></p>
<button onclick="document.getElementById('bulb2').src='pic_bulbon.gif'">Turn on the light</button>
<img id="bulb2" src="pic_bulboff.gif" style="width:50px">
<button onclick="document.getElementById('bulb2').src='pic_bulboff.gif'">Turn off the light</button>
<p></p>
<button onclick = turnOn()>Turn All lights ON</button>
<button onclick = turnOff()>Turn All lights OFF</button>
<button onclick = turnRandomOn()>Turn Any light ON</button>
<script>
function turnOn() {
document.getElementById('bulb0').src='pic_bulbon.gif';
document.getElementById('bulb1').src='pic_bulbon.gif';
document.getElementById('bulb2').src='pic_bulbon.gif';
console.log('All lights were turned on');
}
function turnOff() {
document.getElementById('bulb0').src='pic_bulboff.gif';
document.getElementById('bulb1').src='pic_bulboff.gif';
document.getElementById('bulb2').src='pic_bulboff.gif';
console.log('All lights were turned off');
}
function turnRandomOn() {
let random = Math.floor(Math.random() * 3);
console.log(random);
turnOff();
if (random == 0) {
document.getElementById('bulb0').src='pic_bulbon.gif';
} else
if (random == 1) {
document.getElementById('bulb1').src='pic_bulbon.gif';
} else
if (random == 2) {
document.getElementById('bulb2').src='pic_bulbon.gif';
}
}
</script>
</body>
</html>
Hello there! I'm on my first steps learning JS. I practiced with an interesting self-invented exercise that I just finished, the task consist in creating N-lamps that you can switch On/Off with a button for each lamp, I also added the idea of turning all on/off with just one button and the same for setting on/off a random lamp. The code I shared works fine but I know is not scalable at all since I had to put the lamps by hand. My question is the following:
How can I improve this code to select an HTML element defined by a recursive variable? What I'm trying to say is, for example, instead having a line with the object "document.getElementById('bulb0')"
, how could I change it for something like "document.getElementById('bulbN')"
(where N is variable).
I know it is with an iterative loop but every time I try defining the argument it throws me an error. I tried these two ways:
getElementById('"' bulb N '"').innerHTML
- Defining the argument
('"' bulb N '"')
as a separated variable and later adding it with the same procedure
I will truly appreciate your help, even more if you can share the code
PS: The exercise can be found here https://www.w3schools.com/js/tryit.asp?filename=tryjs_intro_lightbulb
CodePudding user response:
you can do it using template literal strings.
function turnOn() {
for(let i of [0,1,2]) {
document.getElementById(`bulb${i}`).src='pic_bulbon.gif';
}
console.log('All lights were turned on');
}
function turnOff() {
for(let i of [0,1,2]) {
document.getElementById(`bulb${i}`).src='pic_bulboff.gif';
}
console.log('All lights were turned off');
}
Now, what you are doing wrong?
getElementById('"' bulb N '"').innerHTML
// '"' bulb N '"' -> bulb is taken as variable, not like string.
// instead of this you can just use "bulb" N
getElementById("bulb" N).innerHTML
e.g.
let N = 0
console.log("bulb" N)
// now here, bulb is taken as a variable
// this will give you an error. because bulb variable is not defined
// console.log('"' bulb N '"') throw an error
// if you define bulb variable,
{
const bulb = 'bulb'
console.log('"' bulb N '"')
console.log(bulb N)
// you can see '"' bulb N '"' !== bulb N
}
if you need to know more details:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
CodePudding user response:
There are several techniques you can use which I've commented on in the code but I'll mention here with some links to the documentation.
- Use a loop as you suggested to build some HTML using template strings. Push each string into an array, and then
join
that array into one string and add it to the element that contains the lamps:lampsContainer
. - Attach event listeners to the
lampsContainer
, and the buttons. When they're clicked they'll call a handler. With regards tolampsContainer
we're using event delegation - attaching one listener to a container that catches events from its child elements as they "bubble up" the DOM. - If the
lampsContainer
is clicked we first check to see if the element that we clicked on is a button, and then we get that button's lamp element usingpreviousElementSibling
. We toggle the class on that lamp on/off. - The other buttons, as mentioned, have their own handlers. They either turn off (remove the
on
class) or turn on (add theon
class) on all of the lamps. The random button simply toggles one random lamp from the lamp node list on/off.
// Initialise the lamp number,
// and an array to store the HTML string
const n = 4;
const html = [];
// Using a template string create a series of
// sections each containing a button, and a "lamp"
// element. Push each string into the array
for (let i = 0; i < n; i ) {
const str = `
<section >
<div ></div>
<button>lamp${i 1}</button>
</section>
`;
html.push(str);
}
// Cache the elements for the lamps container,
// and the other buttons
const lampsContainer = document.querySelector('.lampsContainer');
const toggleAllOn = document.querySelector('.toggleAllOn');
const toggleAllOff = document.querySelector('.toggleAllOff');
const random = document.querySelector('.random');
// Add the HTML string to the lampsContainer element
lampsContainer.innerHTML = html.join('');
// Add some listeners to the lamps container, and the buttons
lampsContainer.addEventListener('click', handleLamps);
toggleAllOn.addEventListener('click', handleToggleAllOn);
toggleAllOff.addEventListener('click', handleToggleAllOff);
random.addEventListener('click', handleRandom);
// When an element in the lamps container is clicked
// check that it was a button, and then find its lamp
// element. Toggle the lamp `on` class.
function handleLamps(e) {
if (e.target.matches('button')) {
const lamp = e.target.previousElementSibling;
lamp.classList.toggle('on');
}
}
// Find all the lamps in the lamps container,
// and add an `on` class
function handleToggleAllOn() {
const lamps = lampsContainer.querySelectorAll('.lamp');
lamps.forEach(lamp => lamp.classList.add('on'));
}
// Find all the lamps in the lamps container,
// and add an `on` class
function handleToggleAllOff() {
const lamps = lampsContainer.querySelectorAll('.lamp');
lamps.forEach(lamp => lamp.classList.remove('on'));
}
// Find all the lamps in the lamps container,
// find a random lamp from that node list,
// and toggle its `on` class
function handleRandom() {
const lamps = lampsContainer.querySelectorAll('.lamp');
const rnd = Math.floor(Math.random() * lamps.length);
lamps[rnd].classList.toggle('on');
}
.lampContainer { display: flex; flex-direction: row; width:20%; align-items: center; }
.lamp { margin: 0.25em; border: 1px solid #dfdfdf; width: 20px; height: 20px; background-color: white; }
.on { background-color: yellow; }
button, .lamp { border-radius: 5px; }
button { text-transform: uppercase; }
button:hover { cursor: pointer; background-color: lightgreen; }
.buttonsContainer { margin-top: 1em; }
<section ></section>
<section >
<button >Toggle all on</button>
<button >Toggle all off</button>
<button >Toggle random on/off</button>
</section>
CodePudding user response:
- Use Document.createElement() to create element with any iterator
- Then assign attributes. Then simply add that to DOM