0

I cannot seem to figure out why I cannot reference a function that has been defined in another javascript file.

In this specific case, I cannot reference the this.view property which is passed into the TaskCtrlr and utilized in the addTask() function.

Stacktrace:

Uncaught TypeError: Cannot read property 'addTodoTask' of undefined
    at HTMLAnchorElement.addTask (TaskCtrlr.js:21)
addTask @ TaskCtrlr.js:21

app.js

$(function () {
    let model = new TaskModel();
    let view = new TaskView(model);
    let controller = new TaskCtrlr(model, view);
});

TaskCtrlr.js

//Controller
let TaskCtrlr = function (model, view) {
    this.model = model;
    this.view = view;

    this.init();
};

TaskCtrlr.prototype = {
    init: function () {
        this.setupEventHandlers();
    },
    setupEventHandlers: function () {
        //TODO: Define Event Handlers
        document.getElementById('addTask').addEventListener('click', this.addTask);
        document.getElementById('todoRemove').addEventListener('click', this.removeTask);
        document.getElementById('todoComplete').addEventListener('click', this.completeTask);
        document.getElementById('doneRemove').addEventListener('click',  this.removeTask);
    },
    addTask: function () {
        this.view.addTodoTask();
        this.view.getDOMStrings();
    },
    removeTask: function () {
        console.log('Did this do something? 2');
        //1. Do something w/ view
        //2. Do something w/ model
    },
    completeTask: function () {
        console.log('Did this do something? 3');
        //1. Do something w/ view
        //2. Do something w/ model
    }
};

TaskView.js

let TaskView = function (model) {
    this.model = model;
};

let DOMStrings = {
    wow: 'WOWO'
};

TaskView.prototype = {
    updateTodoCount: function () {
        console.log('WOOTYFREAKINGWOO');
    },
    updateDoneCount: function () {

    },
    addTodoTask: function () {
        console.log('hellllooo');
        //this.updateTodoCount();
    },
    completeTask: function () {

    },
    deleteTask: function () {

    },
    getDOMStrings: function () {
        return DOMStrings;
    }
};
Coova
  • 1,818
  • 5
  • 36
  • 63
  • When your event listener is called, `this` is set to be a reference to the DOM element the event occurred on. Have you tried `.addEventListener('click', this.addTask.bind(this));` so that your handler will be called with the `this` value you want to use? – nnnnnn Oct 11 '17 at 02:01
  • I haven't, I am new to JS so I am still trying to pick up things. What does this do exactly? – Coova Oct 11 '17 at 02:04
  • `document.getElementById('addTask').addEventListener('click', this.addTask);` ... when `addTask` is executed, `this` is `document.getElementById('addTask')`, not `controller` – Jaromanda X Oct 11 '17 at 02:04
  • Are you familiar with `this` in other languages such as Java? It [doesn't work the same way in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this), so in some cases you need to use `.bind()` to ensure it has the value you want. – nnnnnn Oct 11 '17 at 02:05
  • I am familiar with 'this' in java, I was under the impression that 'this' was referencing the 'TaskCtrlr' as a whole. I mean what does the .bind(this) do differently in comparison to just calling 'this.addTask'. – Coova Oct 11 '17 at 02:07
  • Read through the MDN page I linked to in that last comment. In JS, the value of `this` within a function depends on how the function is called, not on where the function is defined. Most of the time this works fairly "naturally", but in some cases it seems pretty weird to someone from a Java background. `.bind()` is used to force the value of `this` to be something specific. – nnnnnn Oct 11 '17 at 02:11
  • thanks man @nnnnnn, not sure who wants to throw the answer for this question but it seems to work now. – Coova Oct 11 '17 at 02:14
  • Instead of posting an answer I've closed this as a duplicate question. The existing question I've linked it to doesn't cover `addEventListener()` specifically, but it covers the more general case of passing references to object methods as callback functions, so the same issue, and the answers in that question seem better than the ones in the questions I found that were specific to `addEventListener()` (like [this one](https://stackoverflow.com/questions/1338599/the-value-of-this-within-the-handler-using-addeventlistener)). – nnnnnn Oct 11 '17 at 02:28
  • P.S. By the way, if you're thinking "why can't it be like Java?", the JS way has its own advantages. – nnnnnn Oct 11 '17 at 02:31

0 Answers0