0

So I'm doing a tutorial on one of the videos I found online. In that tutorial, he used IIFE to create mvc model rather than object literals.

I decided to recreate the project using object literals

This is the problem that I am having right now and I'm not sure what the problem is. I suspect it has something to do with scoping problem.

This is the code for the controller and at the end I initiate the init().

var model ={ //Code }
var view = {//Code}

var controller = {
    dom: view.getDom(),
    setEventHandler: function(){
       document.addEventListener("keypress", function(ev){
          if(ev.keyCode === 13){
             this.addItem();
          }
      });
    },

    addItem: function(){
      this.updateMethod();
      // Code
    },
    init: function(){
       this.setupEventHandler();
    },
    updateMethod: function(){
       // Some code
    }


{

controller.init();

Now when I press the enter key to invoke the event, i get an error from the console. It states:

"Uncaught TypeError: this.addItem is not a function at HTMLDocument.[anonymous]"

Question: Why is it not recognizing the addItem()?

The same error message occurs within addItem() when I try to invoke this.updateMethod() too.

One way I found to have this.addItem() to get invoked in the event listener is by using () => rather than using a regular anonymous function declaration.

document.addEventListener("keypress", (ev) => {
   if(ev.keyCode === 13){
      this.addItem();
   {
});

2 Answers2

4

In JavaScript, the value of this is determined by how function is called. In your example, this refers to element on which event is bound.

There are few of ways,

  1. Using Function#bind
  2. Using Arrow Function
  3. Keeping this in variable

Using Function#bind

var model = {};
var view = {};
var controller = {
  dom: view.getDom(),
  setEventHandler: function() {
    document.addEventListener("keypress", function(ev) {
      if (ev.keyCode === 13) {
        this.addItem();
      }
    }.bind(this));
  },
  addItem: function() {
    this.updateMethod();
    // Code
  },
  init: function() {
    this.setupEventHandler();
  },
  updateMethod: function() {
    // Some code
  }
};
controller.init();

Using Arrow Function:

var model = {};
var view = {};
var controller = {
  dom: view.getDom(),
  setEventHandler: function() {
    document.addEventListener("keypress", (ev) => {
      if (ev.keyCode === 13) {
        this.addItem();
      }
    });
  },
  addItem: function() {
    this.updateMethod();
    // Code
  },
  init: function() {
    this.setupEventHandler();
  },
  updateMethod: function() {
    // Some code
  }
};
controller.init();

Using variable holding this context

var model = {};
var view = {};
var controller = {
  dom: view.getDom(),
  setEventHandler: function() {
    var _this = this;
    document.addEventListener("keypress", function(ev) {
      if (ev.keyCode === 13) {
        _this.addItem();
      }
    });
  },
  addItem: function() {
    this.updateMethod();
    // Code
  },
  init: function() {
    this.setupEventHandler();
  },
  updateMethod: function() {
    // Some code
  }
};
controller.init();
Rayon
  • 34,175
  • 4
  • 40
  • 65
0

Question: Why is it not recognizing the addItem()?

...

One way I found to have this.addItem() to get invoked in the event listener is by using () => rather than using a regular anonymous function declaration.

Because with traditional function syntax, the value of this is bound by the caller, so it becomes the bound element. Whereas an arrow function does not bind its own this value, it will use the this from the setEventHandler method, which will be a reference to controller.

Be aware that init calls setupEventHandler but it should be setEventHandler.

Community
  • 1
  • 1