in.spectrum in.spectrum - 7 months ago 24
HTML Question

Function failing after unobtrusively setting attributes

I should note that all of my JavaScript is in the separate base.js file. In the following code I am

1) selecting a div

2) giving it an id and onlcick attribute

3) which calls a function i declare immediately after.

The function fails for some reason. I've tried putting the function first but still no success. The goal is that the divs background and innerHTML will change when the button is pressed. Any ideas why this doesn't work?



var expand = document.querySelector("body div:first-child");
expand.setAttribute("id", "expand");
expand.addEventListener('click', expand);

function expand() {
"use strict";
expand.style.backgroundColor = "red";
document.getElementById("expand").innerHTML = "hi";
}

body{ text-align:center }

body div:first-child{
float:left;width:28px;padding:5px;background:#fff;color:#666;cursor:pointer;
font-size:150%
}

body div:first-child:hover{
background:#222; color:#eee
}

body div:first-child:active{background:#444; color:#fff}

<!doctype html>
<html>
<body>
<div>+</div>
<script src="js/base.js"></script>
</body>
</html>




Answer

Functions and variable declarations are both hoisted to the top of their containing scope, with functions hoisted first.

Because of this, your code is equivalent to:

function expand() {  //hoisted
  "use strict";
  expand.style.backgroundColor = "red";
  document.getElementById("expand").innerHTML = "hi";
}

var expand; //hoisted

expand = document.querySelector("body div:first-child");
expand.setAttribute("id", "expand");
expand.addEventListener('click', expand);

Essentially, the variable expand is overriding your function expand.

To fix it, just give your function a different name:

var expand = document.querySelector("body div:first-child");
expand.setAttribute("id", "expand");
expand.addEventListener('click', fexpand);

function fexpand() {
  "use strict";
  expand.style.backgroundColor = "red";
  document.getElementById("expand").innerHTML = "hi";
}
body{ text-align:center }

body div:first-child{
  float:left;width:28px;padding:5px;background:#fff;color:#666;cursor:pointer;
  font-size:150%
} 

body div:first-child:hover{
  background:#222; color:#eee
}

body div:first-child:active{background:#444; color:#fff}
<!doctype html>
<html>
  <body>
    <div>+</div>
    <script src="js/base.js"></script>
  </body>
</html>