1

I want to call the function "displayTime" in "startTimer" but for some reason I get "Uncaught TypeError: this.displayTime is not a function" in the console.

let endTimer = "0";
let isRunning = false;

//! CLASS
class Timer {
  constructor(endTimer, isRunning) {
    this.endTimer = endTimer;
    this.isRunning = isRunning;
  }

  startTimer() {
    if (this.endTimer === "0") {
      this.endTimer = new Date().getTime() + 1500000;
    }
    displayTime();
    if (this.isRunning === true) {
      this.pauseTimer();
      this.isRunning
    }
    this.isRunning = true;
  }

  displayTime() {
    let now = new Date().getTime();
    let remainingTime = this.endTimer - now;
    let minutes = Math.floor(remainingTime / 1000 / 60);
    let seconds = Math.floor((remainingTime / 1000) % 60);
    if (seconds < 10) {
      seconds = "0" + seconds;
    }
    timer.innerHTML = `<h1>${minutes}:${seconds}</h1>`;
    start.textContent = "STOP"
    this.update = setInterval(this.displayTime, 100);
  }
}

let newTimer = new Timer(endTimer, isRunning);

//! EVENT LISTENERS

start.addEventListener("click", newTimer.startTimer);

I think that I'm missing something obvious, but I don't understand what...

  • 1
    Have you tried referencing it instead as `this.displayTime()`? – GenericUser Jan 14 '22 at 01:08
  • 2
    There's a duplicate for this but the TL;DR is that when you pass the `startTimer` function reference to `addEventListener`, it is detached from the class – Phil Jan 14 '22 at 01:10
  • Does this answer your question? [Is it possible to call a class method with addEventListener?](https://stackoverflow.com/q/21298918/283366) – Phil Jan 14 '22 at 01:12
  • 1
    Does this answer your question? [Maintaining the reference to "this" in Javascript when using callbacks and closures](https://stackoverflow.com/questions/7874723/maintaining-the-reference-to-this-in-javascript-when-using-callbacks-and-closu) – Heretic Monkey Jan 14 '22 at 02:42
  • Thanks for your suggestions, it works! – Giovanni Beccaro Jan 14 '22 at 17:03

3 Answers3

1

Calling displayTime(); without the prepended keyword 'this' is the main issue (line 16 below) as mentioned by GenericUser and Heretic Monkey in the comments above.

You probably already know this but you'll want to define a pauseTimer() method/function as well.

let endTimer = "0";
let isRunning = false;

//! CLASS
class Timer {
constructor(endTimer, isRunning) {
    this.endTimer = endTimer;
    this.isRunning = isRunning;
  }
}

Timer.prototype.startTimer = function() {
    if (this.endTimer === "0") {
        this.endTimer = new Date().getTime() + 1500000;
    }
    this.displayTime(); // this is the important line
    if (this.isRunning === true) {
        this.pauseTimer();
        this.isRunning
    }
    this.isRunning = true;
}

Timer.prototype.displayTime = function() {
    let now = new Date().getTime();
    let remainingTime = this.endTimer - now;
    let minutes = Math.floor(remainingTime / 1000 / 60);
    let seconds = Math.floor((remainingTime / 1000) % 60);
    if (seconds < 10) {
    seconds = "0" + seconds;
    }
    //timer.innerHTML = `<h1>${minutes}:${seconds}</h1>`;
    //start.textContent = "STOP"
    this.update = setInterval(this.displayTime, 100);
}

Timer.prototype.pauseTimer = function() {
    this.isRunning = false;
}

let newTimer = new Timer("0", true);
newTimer.startTimer();

//! EVENT LISTENERS

//start.addEventListener("click", newTimer.startTimer);
Gerald LeRoy
  • 1,227
  • 2
  • 11
  • 17
  • I actually messed up in the code I uploaded and it was indeed "this.displayTimer" that I was calling, so the problem wasn't this one. It was a matter of event listener from what I can see by other comments: `start.addEventListener("click", () => { newTimer.startTimer(); })` This works fine and calls startTimer correctly, same as with the method .bind(). The problem now is that it seems like I can't click the "start" button again, it just doesn't register the click for some reason. Maybe it is because the object isn't the same anymore? I don't really know – Giovanni Beccaro Jan 14 '22 at 15:18
  • It's ok, I solved the issue, thank you! – Giovanni Beccaro Jan 14 '22 at 16:05
1
start.addEventListener("click", newTimer.startTimer.bind(newTimer));
nakzyu
  • 206
  • 1
  • 7
0
class Timer {
    startTimer() {
        // You forgot this keyword
        this.displayTime();
    }
    displayTime() {
        console.log('do something');
    }

}

let newTimer = new Timer();

// addEventListener changes the context of this.
// Using an arrow function will keep 'this' keyword in tact inside startTimer method 
start.addEventListener('click', () => newTimer.startTimer)
ColinT
  • 61
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 14 '22 at 07:43