Here's your code:
document.getElementById("btn" + b).onclick =
document.getElementById("div" + b).innerHTML = "HELLO WORLD"
As far as JavaScript knows, that looks like this to it:
x = y = "HELLO WORLD"
Here's what happens when you do that:
x =
y = "hello world"
console.log("x is:", x)
console.log("y is:", y)
So your code ends up setting the innerHTML
property of #div(b)
and the onclick
property of #btn(b)
! Whoops, that's not what you want.
What you really want is for #div(b)
's innerHTML
to be set when you click on #btn(b)
.
To do that, you need to assign a function, or a callback, to #btn(b)
's onclick
property:
function setTheText(b) {
document.getElementById('div' + b).innerHTML = 'HELLO WORLD'
}
for (var b = 1; b < 5; b++) {
document.getElementById('btn' + b).onclick = function() {
setTheText(b)
}
}
<div id='div1'>Div 1</div>
<div id='div2'>Div 2</div>
<div id='div3'>Div 3</div>
<div id='div4'>Div 4</div>
<button id='btn1'>Button 1</button>
<button id='btn2'>Button 2</button>
<button id='btn3'>Button 3</button>
<button id='btn4'>Button 4</button>
Hmm.. we get an error when we click on the buttons: "Uncaught TypeError
: Cannot set property innerHTML
of null
". Whoops!
Let's investigate. Here's what happens when we replace the setTheText
function's code with something that logs b
:
function setTheText(b) {
console.log(b)
}
for (var b = 1; b < 5; b++) {
document.getElementById('btn' + b).onclick = function() {
setTheText(b)
}
}
<button id='btn1'>Button 1</button>
<button id='btn2'>Button 2</button>
<button id='btn3'>Button 3</button>
<button id='btn4'>Button 4</button>
It always outputs 5! That doesn't make much sense.
Basically the issue is b
gets changed to 5
by the for
loop before JavaScript calls your onclick
function.
So what we really need to do is use a function to create the callback function, so that the callback function can remember what index (b
) it was created with:
function makeSetTheText(b) {
function setTheText() {
document.getElementById('div' + b).innerHTML = 'HELLO WORLD'
}
return setTheText
}
for (var b = 1; b < 5; b++) {
document.getElementById('btn' + b).onclick = makeSetTheText(b)
}
<div id='div1'>Div 1</div>
<div id='div2'>Div 2</div>
<div id='div3'>Div 3</div>
<div id='div4'>Div 4</div>
<button id='btn1'>Button 1</button>
<button id='btn2'>Button 2</button>
<button id='btn3'>Button 3</button>
<button id='btn4'>Button 4</button>
It that's still a bit confusing, don't worry, there's a bunch of really good explanations on how closures and functions that generate functions on StackOverflow here.
If you've made it this far, hopefully:
- You'll have learned a bit about debugging.
- You'll have figured out a solution to your problem.
- You'll have learned a couple fancy JavaScript tricks.
- You'll have some sympathy for the amount of lag I had to deal with while typing this answer, and all the research and testing I did.
Hope this helps!