0

So Im in the midst of writing a connect4 on javascript. I started out using plain variables, giving me a so far functional code checking for vertical victory conditions.

Now I've rewritten it to being objectoriented with classes and stuff. The funny thing is that the code is otherwise basically identical, but for some reason, when I'm trying to concatenate the string representing the id of the HTML element destined to be manipulated, the concatenation fails and the property takes the value "undefined". As far as I can tell, all the variables/properties which are part of this process have been initialized before. The property where this problem occurs is called "IDmarker" in the code below. Another funny thing is that I basically do the exact same thing when building the gamefield, see the property "this.square.id". However, there it works Oo I also tried numerous approaches where I set the respective variables/properties to string explicitely via "toString" method. Didn't work either.

The method in which "this.IDmarker" is manipulated is called in line 44 through this javascriptcode

this.gameFieldContainer.addEventListener('click', this.insertGamepiece,true);

And here is the full JS programcode of my objectoriented variant:

// true if running in a browser, false otherwise
//const isInBrowser = typeof document !== "undefined" && document !== null;
//const isInNode = typeof module !== "undefined" && typeof module.exports !== "undefined";


class gamefield {

    constructor(){
        this.rows = 8;
        this.cols = 8;
        this.squaresize = 50;
        this.boolPlayerColor =  new Boolean ("false");
        this.PlayerColor = "";
        this.RedVictory = 0;
        this.BlueVictory = 0;
        this.VictoryTrigger = 4;
        this.lastCheckfieldVertical = 7;
        this.gameFieldContainer = document.getElementById("gamefield");
        this.column = "";
        this.IDmarker = "";
        this.checkfield = "";
        this.setNextField = "";
        this.verticalCheckfieldID = "";
        //this.buildGamefield();
        //this.insertGamepiece(); macht keinen Sinn zu initialisieren weil dann kein Klickevent vorhanden ist, was zu unerwünschtem verhalten führt.
        //this.checkForVerticalVictory();
        
    }

    buildGamefield(){
        for(var i = 0; i < this.rows; i++){
            for(var j = 0; j < this.cols; j++){
                this.square = document.createElement("div");
                this.gameFieldContainer.appendChild(this.square);
                this.square.id = 's' + i + j;
                this.topPosition = j * this.squaresize;
                this.leftPosition = i * this.squaresize;

                this.square.style.top = this.topPosition + 'px';
                this.square.style.left = this.leftPosition + 'px';

            }
        }
        this.gameFieldContainer.addEventListener('click', this.insertGamepiece,true);
        alert("ID property before insertgamepiece is " + this.IDmarker);   
    }

    insertGamepiece(selection){
        this.boolPlayerColor = !this.boolPlayerColor;
        if(this.boolPlayerColor){
            this.PlayerColor = "red";
        }else{
            this.PlayerColor = "blue";
        }//alert(this.PlayerColor)
         //alert(this.boolPlayerColor)
            document.getElementById("testfield").innerHTML = selection.target.id;
            this.column = selection.target.id.substring(1,2);
            alert("value in column is " + this.column)
        for(var a = 0; a < this.rows; a++){
            this.IDmarker = "s" + this.column + a;
            alert(this.IDmarker)
            this.checkfield = document.getElementById(this.IDmarker);
            if((this.checkfield.style.backgroundColor == "red") || (this.checkfield.style.backgroundColor == "blue")){
                this.setNextField = "s" + this.column + (a - 1);
                document.getElementById(this.setNextField).style.backgroundColor = this.PlayerColor;
                break;
            }if(((this.checkfield.style.backgroundColor != "red") && (this.checkfield.style.backgroundColor != "blue")) && (a == 7)){
                this.checkfield.style.backgroundColor = this.PlayerColor;
            }
        }
        alert("current Playercolorvalue is " + this.PlayerColor);
        //alert(this.checkfield.id);
        //alert("backgroundcolor is set to" + this.checkfield.style.backgroundColor);
        alert("ID property is " + this.IDmarker)
        
        //this.checkForVerticalVictory(this.column)
    }

    checkForVerticalVictory(checkedColumn){
        for(var b = checkedColumn; b <= checkedColumn; b++){
            for(var c = 0; c < this.rows;c++){
                this.verticalCheckfieldID = "s" + b + c;
                this.verticalCheckfield = document.getElementById(this.verticalCheckfieldID);
                if(verticalCheckfield.style.backgroundColor == "red"){
                    this.RedVictory++;
                    //alert("redvictory is " + this.RedVictory);
                }if(verticalCheckfield.style.backgroundColor == "blue"){
                    this.BlueVictory++;
                    //alert("bluevictory is " + this.BlueVictory);
                }if(this.RedVictory == this.VictoryTrigger){
                    alert("Red Wins vertical!")
                    break;
                }if(this.BlueVictory == this.VictoryTrigger){
                    alert("Blue Wins vertical!")
                    break;
                }if((this.RedVictory != 0) && (this.BlueVictory != 0)){
                    this.RedVictory = 0;
                    this.BlueVictory = 0;
                    this.cols--;
                }if((c == this.lastCheckfieldVertical) && ((this.RedVictory < 4) && (this.BlueVictory < 4))){
                    this.RedVictory = 0;
                    this.BlueVictory = 0;
                    //alert("Reset of Vertical");
                }
            }
        }
    }
}


var VierGewinnt = new gamefield();

/*
if (isInBrowser) {
 var VierGewinnt = new gamefield(); // eslint-disable-line no-unused-vars
}

if (isInNode) {
 module.exports = {
  gamefield: gamefield
 };
}
*/
<!Doctype html>
<html>
 <head> 
  <title>Awesome game</title>
  <link rel="stylesheet" type="text/css" href="4style.css">
 <head\>
 <body onload = "VierGewinnt.buildGamefield()">
 
 <h1 id="testfield">yeah buddy </h1>
 
 <p> hier koennte ihr 4gewinnt stehen </p>
 <div id = "gamefield"></div>
 </body>
 <script type="text/javascript" src="4GewinntObjektorientiert.js"></script> 
</html>

Just for reference, I'll give you the non-object-oriented code as well, you can easily run it on your browser if you like. Therefore I'll also include the css code.

var rows = 8;
var cols = 8;
var squareSize = 50;
var boolPlayerColor =  new Boolean ("false")
var PlayerColor = ""
var RedVictory = 0;
var BlueVictory = 0;
var VictoryTrigger = 4;
var lastCheckfieldVertical = 7;


var gameFieldContainer = document.getElementById("gamefield");

for(i = 0; i < rows; i++){
 for(j = 0; j < cols; j++){
  var square = document.createElement("div");
  gameFieldContainer.appendChild(square);
  square.id = 's' + i + j;
  var topPosition = j * squareSize;
  var leftPosition = i * squareSize;
  
  square.style.top = topPosition + 'px';
  square.style.left = leftPosition + 'px';
 }
}

gameFieldContainer.addEventListener("click", insertGamepiece,true);

function insertGamepiece(selection){
 boolPlayerColor = !boolPlayerColor
 if(boolPlayerColor){
  PlayerColor = "red";
 }else{
  PlayerColor = "blue";
 }//alert(PlayerColor)
 document.getElementById("testfield").innerHTML = selection.target.id;
 //selection.target.style.backgroundColor = "red";
 var column = selection.target.id.substring(1,2);
 //alert("column ist " + column);
 //Structure to put the respective gamepiece
 for(a = 0; a < rows; a++){
  var ID = 's' + column + a;
  var checkfield = document.getElementById(ID)
  if((checkfield.style.backgroundColor == "red") || (checkfield.style.backgroundColor == "blue")){
   var setNextField = 's' + column + (a - 1);
   document.getElementById(setNextField).style.backgroundColor = PlayerColor;
   break;
   
  }if(((checkfield.style.backgroundColor != "red") && (checkfield.style.backgroundColor != "blue")) && (a == 7)){
   checkfield.style.backgroundColor = PlayerColor;
  }
  /*
  if((column + a) == (column + 7)){
  var destination = column + a;
  alert("destination ist " + destination);
  document.getElementById("testparagraph").innerHTML = destination.toString();
  }*/
 }
 checkForVerticalVictory(column);
 //checkForHorizontalVictory(); nested into function "checkForVerticalVictory"
}

function checkForVerticalVictory(checkedColumn){
 for(b = checkedColumn; b <= checkedColumn; b++){
  for(c = 0; c < rows; c++){
   var verticalCheckFieldID = 's' + b + c
   var verticalCheckField = document.getElementById(verticalCheckFieldID);
   if(verticalCheckField.style.backgroundColor == "red"){
    RedVictory++;
    //alert("redvictory is " + RedVictory);
   }if(verticalCheckField.style.backgroundColor == "blue"){
    BlueVictory++;
    //alert("bluevictory is " + BlueVictory);
   }if(RedVictory == VictoryTrigger){
    alert("Red Wins vertical!")
    break;
   }if(BlueVictory == VictoryTrigger){
    alert("Blue Wins vertical!")
    break;
   }if((RedVictory != 0) && (BlueVictory != 0)){
    RedVictory = 0;
    BlueVictory = 0;
    cols--;
   }if((c == lastCheckfieldVertical) && ((RedVictory < 4)&&(BlueVictory < 4))){
    RedVictory = 0;
    BlueVictory = 0;
    //alert("Reset of Vertical");
   }
  }
 }
}
body {
    margin: 60px auto;
    width: 70%;
    max-width: 950px;
}

h1 {
    font-size: 3em;
    font-family:'Helvetica', 'Arial', 'Sans-Serif';
}


#gamefield {
 position:relative;
 margin:0 auto 2em auto;
 width:500px;
 height:500px;
}

#gamefield div {
 position:absolute;
 -webkit-box-sizing: border-box; /* Safari 3.0 - 5.0, Chrome 1 - 9, Android 2.1 - 3.x */
 -moz-box-sizing: border-box;    /* Firefox 1 - 28 */
 box-sizing: border-box;         /* Safari 5.1+, Chrome 10+, Firefox 29+, Opera 7+, IE 8+, Android 4.0+, iOS any */
 background: #f6f8f9; /* Old browsers */
 border: 1px solid #ddd;
 width:50px;
 height:50px;
}
<!Doctype html>
<html>
 <head> 
  <title>Awesome game</title>
   <link rel="stylesheet" type="text/css" href="4style.css">
 <head\>
 <body>
 
 <h1 id="testfield">yeah buddy </h1>
 
 <p> hier koennte ihr 4gewinnt stehen </p>
 <div id = "gamefield"></div>
 </body>

</html>

<script type="text/javascript" src="4gewinnt.js"></script>
Narktor
  • 977
  • 14
  • 34
  • 3
    When you set up an event handler to call a method, you have to explicitly bind the function to `this` or else `this` will be `undefined` when the handler is invoked. – Pointy Apr 05 '18 at 13:55
  • There's also at least one spot where you use "`column`" when you mean "`this.column`." – Daniel Beck Apr 05 '18 at 14:03
  • Please show us where and how you call the method in which `this.IDMarker` does not work – Bergi Apr 05 '18 at 14:05
  • I edited in the "this.column" where "this" was lacking :D thanks. – Narktor Apr 05 '18 at 14:06
  • Hint: `this.boolPlayerColor = new Boolean ("false");` is not what you want. Neither do you want to construct an object, nor from a thruthy (non-empty) string. Just use `this.boolPlayerColor = false;` – Bergi Apr 05 '18 at 14:07
  • I edited in the requested answer @Bergi – Narktor Apr 05 '18 at 14:09
  • Okay, but the "new" approach at least didn't pose any problems so far, the property behaves as it should to my knowledge :D – Narktor Apr 05 '18 at 14:10
  • @Pointy how do I achieve "explicitely binding" the function to "this"? What do I have to do? – Narktor Apr 05 '18 at 14:22
  • `this.gameFieldContainer.addEventListener('click', this.insertGamepiece.bind(this),true);` – Pointy Apr 05 '18 at 14:24
  • @Narktor Well it did work as if you started with `true`, so it's at least very misleading. – Bergi Apr 05 '18 at 14:24
  • @Bergi ah ok, I didnt notice that (myfault...^^) and yeah youre right, thats definitely misleading :D – Narktor Apr 05 '18 at 14:25
  • @Pointy Baam that worked, THANKS! :D – Narktor Apr 05 '18 at 14:27

0 Answers0