Search code examples
javascriptgetelementsbyclassname

Javascript Internal class not found by document.getElementByClassName


I am making a Physics engine that utilizes JavaScript to create boxes that have the properties of physics applied to them in scale of the window size. However, the class called box that contains all the physical properties of these boxes cannot be found by the function document.getElementByClassName("box").

I am trying to assign a variable boxelem to contain the location properties of each individual box so that I can integrate mouse manipulation into my program in the future. I have tried doing this through the code:
var boxelem = document.getElementsByClassName("box"); and then adding a mouse over event listener to boxelem.

Necessary Code:

var canvas;
var ctx;
var box = [];
var boxelem;

//Startup Code
window.onload = function(e) {
    canvas = document.getElementById("c");
    ctx = canvas.getContext("2d");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    box = [new box(10, 20, "cyan"), new box(299, 40, "red"), new box(90, 50,
      "black"), new box(29, 20, "turquoise")];
    boxelem = document.getElementsByClassName("box");
    noscroll();
    update();
  }

  //Physic Clock (For real-time physics)
var clock = {
    lasttick: 0,
    tick: function() {
      var td = performance.now() - this.lasttick;
      this.lasttick = performance.now();
      return td / 1000;
    },
    reset: function() {

    }
  }

  //Box objects be created here (Box Class)
var box = function(x, y, color) {
  var _this = this;
  //First Spawn Physics and Settings
  _this.x = Math.random() * (canvas.width - 50);
  _this.y = Math.random() * (canvas.height - 50);
  _this.vx = 0;
  _this.vy = Math.random() * 150;
  _this.ax = 0;
  _this.ay = 440;
  _this.color = color;

  _this.draw = function() {
      ctx.fillStyle = _this.color;
      ctx.fillRect(_this.x, _this.y, 50, 50);
    }

    //Normal Physics
  _this.update = function(t, mX, mY) {
    if (mX != 0) {
      _this.x += _this.vx * t;
      _this.vx += mX * t;
    } else {
      _this.x += _this.vx * t;
      _this.vx += _this.ax * t;
    }
    _this.y += _this.vy * t;
    _this.vy += _this.ay * t;

    //Boundary Creation
    if ((_this.y + 55) > canvas.height) {
      _this.vy -= _this.ay * t;
      _this.vy = 0;

    }
    if ((_this.x + 55) > canvas.width) {
      _this.vx -= _this.ax * t;
      _this.vx = 0;
    }
    if ((_this.y) < 0) {
      _this.vy -= _this.ay * t;
      _this.vy = 0;
      _this.y = (canvas.height + 20);
    }
    if ((_this.x) < 0) {
      _this.vx -= _this.ax * t;
      _this.vx = 0;
    }
  }
}

//Get mouse position if over a box
var pageX = 0;
var pageY = 0;
for (var z = 0; z < box.length; z++) {
  boxelem.addEventListener("mouse", mPos, false);
}

The event listener at the bottom gives an error because boxelem is not defined due to the elements not being found by getElementsByClassName. HTML Code:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
     <script type=text/javascript src="Physics.js"></script>
     <meta charset="utf-8" />
     <title>Physics Engine of Boxes</title>
 </head>
 <body>
     <canvas id="c"></canvas>
</body>
</html>

I have looked at (Unobtrusive Javascript-Basic Implementation: How do I bind all elements of a particular class to a function in Javascript?) and (Change an element's class with JavaScript) but am unsure how to apply it to my issue.


Solution

  • This body of your loop is not accessing the index. Also, the .length you're using is from the box function instead of the boxelem collection.

    This:

    for (var z = 0; z < box.length; z++) 
    {
      boxelem.addEventListener("mouse", mPos, false);
    }
    

    should be this:

    for (var z = 0; z < boxelem.length; z++) 
    {
      boxelem[z].addEventListener("mouse", mPos, false);
    }
    

    As D Simon pointed out below, boxelem is undefined because you're not populating that variable until after the DOM loads. You should be sure to fetch those items before trying to use that variable.


    If you move all the code to window.onload, it should work. Note that window.onload doesn't run until all resources are loaded. You may want to use a different event that fires sooner, but that's another topic.

    //Startup Code
    window.onload = function(e) {
        var canvas = document.getElementById("c");
        var ctx = canvas.getContext("2d");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        var box = [new box(10, 20, "cyan"), new box(299, 40, "red"), new box(90, 50,
          "black"), new box(29, 20, "turquoise")];
        var boxelem = document.getElementsByClassName("box");
        noscroll();
        update();
    
        //Physic Clock (For real-time physics)
        var clock = {
            lasttick: 0,
            tick: function() {
              var td = performance.now() - this.lasttick;
              this.lasttick = performance.now();
              return td / 1000;
            },
            reset: function() {
    
            }
          }
    
        //Box objects be created here (Box Class)
        var box = function(x, y, color) {
          // ...implementation...
        }
    
        //Get mouse position if over a box
        var pageX = 0;
        var pageY = 0;
        for (var z = 0; z < boxelem.length; z++) {
          boxelem[z].addEventListener("mouse", mPos, false);
        }
    }