0

I'm running into the undefinded error when trying to access the this.numberObject from another function init.

I'm pretty sure it's because my this keyword is referencing the window object.

My problem is that I can't figure out an elegant way to structure my code.

Current Code:

class IncrementNumbers {
  constructor() {
    this.numberObject = document.querySelector(".incrementNum");
    if (this.numberObject != null) {
      console.log(this.numberObject.innerHTML);
      this.num = this.numberObject.innerHTML;
      this.events();
    }
  }

  events() {
    console.log("events function ran");
    this.init();
  }

  init() {
    let target = 345;
    let current = 0;
    function addOneToElement() {
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current; <---- ERROR HERE
    }
    let addOne = setInterval(addOneToElement, 10);
  }
}

export default IncrementNumbers;

Error:

IncrementNumbers.js:44 Uncaught TypeError: Cannot set property 'innerHTML' of undefined

I can fix the error by adding in

  this.numberObject = document.querySelector(".incrementNum");

to the following function

init() {
    let target = 345;
    let current = 0;
    function addOneToElement() {
      this.numberObject = document.querySelector(".incrementNum");  <--- ADDED HERE
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current;
    }
    let addOne = setInterval(addOneToElement, 10);
  }

However this feels a bit redundant because I'm already referencing the element Object in my constructor. I'd like the function, init to run once the page has loaded.

Is there a better way?

Thank you

2
  • Change this.init(); to init.call(this). Commented Nov 2, 2020 at 21:05
  • You can either convert addOneToElement to an arrow function, or keep the non-arrow finction, but bind it to the this variable. Commented Nov 2, 2020 at 21:08

2 Answers 2

1

Your problem seems to come from a misspropagation of the this object.
In your function init you set a new function named addOneToElement that is called inside of a setInterval, this setInterval instance does not have access to the this element of your class.

To fix the problem you could try to do something like

class IncrementNumbers {
  constructor() {
    this.numberObject = document.querySelector(".incrementNum");
    if (this.numberObject != null) {
      console.log(this.numberObject.innerHTML);
      this.num = this.numberObject.innerHTML;
      this.events();
    }
  }

  events() {
    console.log("events function ran");
    this.init();
  }

  init() {
    let target = 345;
    let current = 0;
    function addOneToElement() {
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current; // <---- ERROR HERE
    }
    let addOne = setInterval(addOneToElement.bind(this), 10);
  }
}

export default IncrementNumbers;
let addOne = setInterval(addOneToElement.bind(this), 10);

Where you bind the this instance of your class to the function addOneToElement.

Sign up to request clarification or add additional context in comments.

Comments

1

The problem is the inner function addOneToElement that creates its own this context within init.

A simple fix would be to use arrow functions which don't have a this context:

class IncrementNumbers {
  init() {
    let target = 345;
    let current = 0;
    // Use an arrow function here.
    const addOneToElement = () => {
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current; <---- ERROR HERE
    }
    let addOne = setInterval(addOneToElement, 10);
  }
}

Another option would be to bind the this context to addOneToElement:

let addOne = setInterval(addOneToElement.bind(this), 10);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.