0

Clicking the buttons 'hi' and 'helo' must change the content of '.admin-text' to the respective text according to the plan, but it simply changes it to 'undefined'.

var admin_text = document.querySelector('.admin-text');

var infra_btns = [document.getElementById('hi'), document.getElementById('helo')];


var infra_html = ["<p>hi</p>", "<p>helo</p>"];

for(var i = 0; i < 2; i++)
{
  infra_btns[i].addEventListener('click', function() {
    admin_text.innerHTML = infra_html[i];
  });
}
<div class="admin">
  <div class="admin-nav">
    <button class="adminbtns" id="hi">hi</button>
    <button class="adminbtns" id="helo">helo</button>
  </div>

  <div class="admin-text">

  </div>
</div>
Dexter Bengil
  • 5,995
  • 6
  • 35
  • 54
Cracin
  • 503
  • 1
  • 8
  • 19

2 Answers2

5

You're almost there - you need to use let instead of var in your for-loop, otherwise i equals 2 in all your listener functions:

var admin_text = document.querySelector('.admin-text');

var infra_btns = [hi, helo];


var infra_html = ["<p>hi</p>", "<p>helo</p>"];

for (let i = 0; i < 2; i++) {
  infra_btns[i].addEventListener('click', function() {
    admin_text.innerHTML = infra_html[i];
  });
}
<div class="admin">
  <div class="admin-nav">
    <button class="adminbtns" id="hi">hi</button>
    <button class="adminbtns" id="helo">helo</button>
  </div>
  <div class="admin-text"></div>
</div>

This happens because variables declared using var have function scope, and i in your listener functions is passed by reference, not by value, so all your listeners share the same i. After the last iteration the last thing the for-loop does is i++, so i equals 2. So your listener tries to access infra_html[2] which is undefined because your array does not have an element with that index.

This post explains it in detail: JQuery not appending correct value to unordered list

connexo
  • 53,704
  • 14
  • 91
  • 128
3

The problem is in the loop you have

for(var i = 0; i < 2; i++)
{
  infra_btns[i].addEventListener('click', function() {
    admin_text.innerHTML = infra_html[i];
  });
}

When the client event handler triggers i will be 3, as the loop has ended previously. You should create a closure.

for(var i = 0; i < 2; i++)
{
   infra_btns[i].addEventListener('click', (function(index) {
      return function () {
         admin_text.innerHTML = infra_html[index];
      }
   })(i));
}

or use let to create block scoped variable as shown in other answer

Jiby Jose
  • 3,745
  • 4
  • 24
  • 32
  • I'd recommend giving the IIFE parameter a different name to make it clear that this is not the outer `i`. – connexo Feb 25 '18 at 11:19