0

I have the following code and when I click on a button, I want the alert to display the string in the prizes array that corresponds to the index equal to the button's number. I currently receive "Fresh Laundry!".

<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

<script type="text/javascript">
  var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
  for (var btnNum = 0; btnNum < prizes.length - 1; btnNum++) {
    document.getElementById('btn-' + btnNum).onclick = function() {
      alert(prizes[btnNum]);
    };
  }
</script>
Dij
  • 9,761
  • 4
  • 18
  • 35
Drew H
  • 5
  • 1
  • 3

5 Answers5

1

your code has a problem relating to closures, btnNum you are using in alert(prizes[btnNum]) has a value of 2 after the loop is finished. It would be better if you just use id of each element in event handler to get the prize from array, something like this:

<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

<script type="text/javascript">
  var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
  for (var btnNum = 0; btnNum < prizes.length; btnNum++) {
    document.getElementById('btn-' + btnNum).onclick = function() {
      var id = this.id;
      alert(prizes[id.charAt(id.length-1)]);
    };
  }
</script>
Dij
  • 9,761
  • 4
  • 18
  • 35
0

It's because when your closure is called, btnNum is already set to 32.

You can do something like this:

<script type="text/javascript">
  var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
  for (var btnNum = 0; btnNum < prizes.length - 1; btnNum++) {
    (function(_btnNum) {
      document.getElementById('btn-' + _btnNum).onclick = function() {
        alert(prizes[_btnNum]);
      }
    })(btnNum);
  }
</script>
obe
  • 7,378
  • 5
  • 31
  • 40
0

You can try setting a value in the button:

<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

<script type="text/javascript">
  var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
  for (var btnNum = 0; btnNum < prizes.length - 1; btnNum++) {
    document.getElementById('btn-' + btnNum).value = btnNum;
    document.getElementById('btn-' + btnNum).onclick = function() {
      alert(prizes[this.value]);
    };
  }
</script>

See for you self what method u like most

onno204
  • 71
  • 8
0

Why not

  var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
  function clickHandler (btnNum) {
    alert(prizes[btnNum])
  };
<button id="btn-0" onclick="clickHandler(0)">Button 1!</button>
<button id="btn-1" onclick="clickHandler(1)">Button 2!</button>
<button id="btn-2" onclick="clickHandler(2)">Button 3!</button>

Sure onclick handlers in HTML are kinda terrible, but without more context behind the contrived code example, might as well.

To make it a little neater you could try

var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
function clickHandler (event) {
  alert(prizes[this.id.replace('btn-', '')])
};
elems = document.getElementsByClassName('click-me');
for (var i=0; i<elems.length; i++) {
  elems[i].onclick = clickHandler;
}
<button id="btn-0" class="click-me">Button 1!</button>
<button id="btn-1" class="click-me">Button 2!</button>
<button id="btn-2" class="click-me">Button 3!</button>
Anthony Manning-Franklin
  • 4,408
  • 1
  • 18
  • 23
0

You are experiencing the side-effects of closure.

Closures are functions which keep tracks of the functions in which they are declared. In this case, onclick function, is a closure, which is keeping track of btnNum variable. As btnNum is increasing after each iteration, onClick function also updates the btnNum inside it's implementation, and hence you see Fresh Laundary each time.

To fix this, you can create an IIFE (Immediately Invoked Function Expression) (function() {} }() and pass on the btnNum. This will limit the scope of the closure function, which will refer to the intended btnNum only.

<button id="btn-0">Button 1!</button>
<button id="btn-1">Button 2!</button>
<button id="btn-2">Button 3!</button>

<script type="text/javascript">
  var prizes = ['A Unicorn!', 'A Hug!', 'Fresh Laundry!'];
  for (var btnNum = 0; btnNum < prizes.length; btnNum++) {
    (function(btnNum) {
      document.getElementById('btn-' + btnNum).onclick = function() {
        alert(prizes[btnNum]);
      };
    })(btnNum)
  }
</script>
Anurag Singh Bisht
  • 2,683
  • 4
  • 20
  • 26