Search code examples
javascriptoopscopethisobject-literal

Property variable undefined in object literal using this keyword


I'm trying to understand OOP and this is my first real attempt. I'm confused why the word property variable in the init object is not available in the checkLetter function console.log even though I'm using the this keyword. In my pickWord function I'm able to use this.word with no issues. How can I make the word variable and this.word.length available to checkLetter?

var words = ["cancer", "aids", "stroke", "diabetes" ];

var keys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];

point = 0;

var init = {
  word: "",
  word_index: 0,
  point_status: 0,
  pickWord: function(){
    this.word = words[this.word_index];  
    this.displayDashes(this.word);
  },

  displayDashes: function(word){
    for(var i = 0; i< word.length; i++){
      var blankLetter = document.createElement("div");

      var hiddenletter = document.createTextNode(word[i]);
      blankLetter.appendChild(hiddenletter);

      blankLetter.classList.add('dashes');

      var wordHolder = document.getElementById('wordHolder');

      wordHolder.appendChild(blankLetter);


    }

  },

  addKeys: function(){
    for (var i = 0; i < keys.length; i++){
      var key = document.createElement("div");
      key.classList.add('keys');

      key.onclick = this.checkLetter;

      var letter = document.createTextNode(keys[i]);
      key.appendChild(letter);

      var keyboard = document.getElementById('keyboard');

      keyboard.appendChild(key);


    }
  },

  checkLetter: function(){

   var letterElems = document.getElementsByClassName('dashes');

   this.style.backgroundColor = 'blue';

   for(var i = 0; i < letterElems.length; i++){
     if(this.innerHTML == letterElems[i].innerHTML){
       letterElems[i].style.backgroundColor = 'white';
       pointStatus = point++;

     }
   }
  // checkPoints(pointStatus);
   // console.log(point); 
   console.log("the word: " + this.word); 

   if(point == this.word.length){
      alert('you won ' + point + " points so far!");
      this.nextWord();

    }  
  },


  nextWord: function(){
      alert('im inside nexword');
      this.word_index++;
      this.pickWord();
  }
}

init.pickWord();
init.addKeys();
// init.displayDashes();

Solution

  • The key.onclick event handler is called in the context of the element. So 'this' is the element. There are numerous ways to work around this issue. One such way is to bind the value of 'this' to the init object:

    key.onclick = this.checkLetter.bind(this);
    

    Edit: if you need access to the event handler's element, you can include the event as a function parameter, and access the element using the 'currentTarget' property. E.g. evt.currentTarget.

    checkLetter: function(evt){
        var elem = evt.currentTarget;