1

There is a Class and inside if this class I'm trying to fill up an array winch was defined in 'constructor'.

 class ClassA {

   constructor(){
      ...
      this.place = [];
   }

   fillUp() {
      fetch(path)
        .then(function(response) {
          return response.json();
        }).then(function(result) {

         this.place.push({"result":result})
        })
    }
 }
inst = new ClassA();   
inst.fillUp();

As a result i got this error: TypeError: Cannot read property 'place' of undefined. Where could be the problem?

Iliagua
  • 15
  • 5
  • 2
    Does this answer your question? [Why is 'this' undefined inside class method when using promises?](https://stackoverflow.com/questions/34930771/why-is-this-undefined-inside-class-method-when-using-promises) – Caramiriel Nov 22 '19 at 15:42
  • Because you are inside a promise thenable, "this" now points to the thenable. You will need to do something like const self = this; as the first line in your fillUp function. Then instead of writing this.place.push, you would write self.place.push. – Freddie Nov 22 '19 at 15:43

5 Answers5

1

You can solve your issue by using an arrow function expression in the callback attempting to push into the array. The problem with using a typical function expression is that it creates its own binding to the this keyword. Arrow functions on the other hand:

An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope, an arrow function ends up finding the this from its enclosing scope.

Therefore, you if you use an arrow function in the callback, the function will take this from it's enclosing scope (i.e.: the ClassA object).

Here's a demo of how it might work:

const mockFetch = new Promise((resolve, reject) => {
  console.log('Fetching data..please wait..')
  setTimeout(() => resolve({
    json: () => '{ data: \'Some response data\'}'
  }), 1500)
});


class ClassA {
  constructor() {
    this.place = [];
  }

  fillUp() {
    mockFetch.then(function(response) {
      return response.json();
    }).then(result => {
      this.place.push({
        "result": result
      });
      console.log(this.place);
    })
  }
}

inst = new ClassA();
inst.fillUp();
Tom O.
  • 5,730
  • 2
  • 21
  • 35
0

this in javascript is weird. Depending on how the code/function is called on the object, it may return values you did not expect. If you are using modern javascript, you should use short arrow notation. This will preserve what this is binded to. Otherwise, you will have to add .bind(this) to the function where you are referencing this:

fetch(path)
    .then((response)=>{
        return response.json();
    }).then((result)=>{
        this.place.push({"result":result})
    })

surgiie
  • 3,947
  • 3
  • 12
  • 11
0

Use arrow function.

 class ClassA {

   constructor(){
      ...
      this.place = [];
   }

   fillUp = () => {
      fetch(path)
        .then(function(response) {
          return response.json();
        }).then(function(result) {

         this.place.push({"result":result})
        })
    }
 }
inst = new ClassA();   
inst.fillUp();
Afia
  • 683
  • 5
  • 17
0

The promise handlers are different functions with different this values.

To make the this equal inside, you can use arrow functions, which inherit this from where they've been defined:

class ClassA {

   constructor(){
      ...
      this.place = [];
   }

   fillUp() {
      fetch(path)
        .then(response =>  response.json())
        .then(result => {
          this.place.push({"result":result})
        })
      }
    }
inst = new ClassA();   
inst.fillUp();

Or, .bind() the functions:

class ClassA {

   constructor(){
      ...
      this.place = [];
   }

   fillUp() {
      fetch(path)
        .then(function(response) {
          response.json()
        })
        .then((function(result) {
          this.place.push({"result":result})
        }).bind(this))
      }
    }
inst = new ClassA();   
inst.fillUp();
FZs
  • 16,581
  • 13
  • 41
  • 50
  • or the classic `var that = this;` before the promise starts. – TKoL Nov 22 '19 at 15:52
  • @TKoL Yes, but as of ES6, that's not the best method. However, in pre-ES6 that was the only one... – FZs Nov 22 '19 at 15:53
  • Thanks - I rewrite the function with ES6 arrow notation and 'this' works now without bind() or const that = this; – Iliagua Nov 22 '19 at 16:12
  • @TKoL Just a typo, I've meant to write pre-ES5, as `.bind()` was added in it. – FZs Nov 22 '19 at 18:26
0
.then((result) => {
 this.place.push({"result":result})
})

works great. Than you!

Iliagua
  • 15
  • 5