ulubeyn ulubeyn - 3 months ago 15
TypeScript Question

cannot get 'this' of component inside subscribe function

My question is quite similar to these, but i did not solve my problem;

cannot access to this of component in subscribe function

'this' scope in typescript callback function

Cannot Access Component Variables in Subscribe when using chrome inspector

unable to get component variables inside a RxJS subscribe() function

Here is my typescript component class:

export class Test{
x: string;
}

export class TestComponent implements OnInit{
test: Test;

constructor(private testService: TestService){}

ngOnInit(){
this.testService.getTest()
.subscribe((res) => { this.test = res.test;}, ...);
console.log(this.text.x) //it becomes undefined
}
}


I am using gulp-typescript, and outputs are like these;

//when targeting es6

let testComponent = class TestComponent ... {
constructor(testService){
this.testService = testService;
}

ngOnInit(){
this.testService.getTest()
.subscribe((res) => {this.test = res.test;}, ...);
console.log(this.text.x)
}
}

//when targeting es5

var TestComponent = (function(){
function TestComponent(testService){
this.testService = testService;
}

TestComponent.prototype.ngOnInit = function(){
var _this = this;
this.testService.getTest()
.subscribe(function (res) { _this.test = res.test }, ...);
console.log(this.text.x)
}
}())


When I want to try to reach 'this.test.x' I get the following error from browser with both outputs;

EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property 'x' of undefined


When I log the
this.test
, it is
undefined
. My TestService is injected properly, request come to my api and
res.test
includes what i need but i cannot use with
this.test
because it is always undefined. I do not know where I am doing wrong. Is there anyone else who can help me? Finally, I want to ask that, which one should I target when considering browser compatibility etc., es5 or es6?

Answer

Move the console.log statement inside of the arrow function.

ngOnInit(){
          this.testService.getTest()
               .subscribe((res) => {
                 this.test = res.test;
                 console.log(this.text.x)
          }, ...);

     }

If you had other things you wanted to do with this.test, then you're going to have to move those inside too (or, add another function and call that from inside the callback). Basically, if you have a service that returns an Observable, that means the callback will not run in the same "frame" that you called the function. In your original code this was the order of operations:

  1. getTest is called, an AJAX operation is started
  2. console.log called, prints undefined.
  3. User gets a second of UI time with not much happening as the request communicates with the server
  4. Request finishes, subscribe(() => callback is called. this.test is set.