Reputation: 1009
I'm calling this.getAllJobsAPI(); in the render function.
This successfully calls the getAllJobsAPI (as given below) and I'm able to retrieve job name from the JSON array of jobs.
getAllJobsAPI(){
var headers = new Headers();
headers.append('Authorization', 'Basic YWRtaW46YWRtaW4=');
fetch('http://localhost:8080/api/json', {headers: headers})
.then((result) => {
// Get the result
// If we want text, call result.text()
return result.json();
}).then((jsonResult) => {
// get all jobs
var jobs = [];
Object.keys(jsonResult.jobs).forEach(function(key) {
jobs.push(jsonResult.jobs[key].name);
var job = jsonResult.jobs[key].name;
console.log(job);
this.getLastBuildAPI(job);
});
//var a = 'meetup';
//this.getLastBuildAPI(a);
console.log(jsonResult);
})
}
But calling this.getLastBuildAPI(job); within the for each loop throws "Uncaught (in promise) TypeError: Cannot read property 'getLastBuildAPI' of undefined" error. But If I hardcode a name variable in the end of the function and call this.getLastBuildAPI(a); I could get the success response.
Could someone tell me why I'm not able to call this.getLastBuildAPI(job); within for-each of the JSON array? Note that I'm able to see job variable in console.
Thanks,
Upvotes: 1
Views: 600
Reputation: 8209
Because this
inside the resolve callback is undefined
(as it's a different context), while when it's outside the callback this
is the object you expect. You can reference this
var storing it first.
getAllJobsAPI(){
var headers = new Headers();
headers.append('Authorization', 'Basic YWRtaW46YWRtaW4=');
var self = this;
fetch('http://localhost:8080/api/json', {headers: headers})
.then((result) => {
// Get the result
// If we want text, call result.text()
return result.json();
}).then((jsonResult) => {
// get all jobs
var jobs = [];
Object.keys(jsonResult.jobs).forEach(function(key) {
jobs.push(jsonResult.jobs[key].name);
var job = jsonResult.jobs[key].name;
console.log(job);
self.getLastBuildAPI(job);
});
//var a = 'meetup';
//this.getLastBuildAPI(a);
console.log(jsonResult);
})
You can also apply another approaches.
bind
method.The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Object.keys(jsonResult.jobs).forEach(function(key) {
jobs.push(jsonResult.jobs[key].name);
var job = jsonResult.jobs[key].name;
console.log(job);
this.getLastBuildAPI(job);
}.bind(this));
arrow
functions.Until arrow
functions, every new
function defined its own this
value.
For instance, this
can be a new object in the case of a constructor.
function Person(age){
this.age=age;
console.log(this);
}
let person=new Person(22);
Or this
can points to the base
object if the function created can be accessed like obj.getAge()
.
let obj={
getAge:function(){
console.log(this);
return 22;
}
}
console.log(obj.getAge());
An arrow
function does not create its own this
, it's just used the this
value of the enclosing
execution context
. In the other hand, arrow
function uses this
of parent scope.
Object.keys(jsonResult.jobs).forEach((key) => {
jobs.push(jsonResult.jobs[key].name);
var job = jsonResult.jobs[key].name;
console.log(job);
this.getLastBuildAPI(job);
});
Upvotes: 3
Reputation: 22474
You've passed a normal function
to forEach
which changed the context. If you want to preserve the context use an arrow function or, alternatively, you could create a new variable to keep a reference to this
.
Using an arrow function:
Object.keys(jsonResult.jobs).forEach(key => {
.....
this.getLastBuildAPI(job);
});
Keeping a reference to this
:
var that = this;
Object.keys(jsonResult.jobs).forEach(function(key) {
....
that.getLastBuildAPI(job);
});
Upvotes: 2