Reputation: 478
Have a look at the code follows.
I am creating a class with a constructor in which I am creating some variables. Furthermore I am creating some asynchronous functions, of which 3 are very similar and the last one is able to call the others.
class Project {
data = {};
constructor(project, api) {
for (const key in project) {
this.data[key] = project[key];
}
this.logger = new Logger(
document.querySelector("#output"),
`Project= ${this.data.projectId}: `
)
this.api = api;
}
async getTasks() {
return await this.api.getTasksAsync(this.projectId);
}
async getRequirements() {
return await this.api.getRequirementsAsync(this.projectId);
}
async getReleases() {
return await this.api.getReleasesAsync(this.projectId);
}
async getToDraw(type) {
let func = this[`get${type}`];
console.log(func);
let result = [];
for (let item of await func()){
result.push(toTaskItem(item));
}
return result;
}
}
The error I get when executing the function 'getToDraw' on an initiated object of the class 'Project' (above):
I am calling the function as follows:
async drawDiagram(sender){
let projectID = this.getSelectedValue("projectSelector");
if (projectID !== "-1") {
let project = this.projects.filter((project) => project.data.ProjectId === parseInt(projectID))[0];
if (document.querySelector("#typeSelector").selectedOptions[0].innerText === "Full"){
// TODO:
} else {
let list = await project.getToDraw(document.querySelector("#typeSelector").selectedOptions[0].innerText);
console.log(list);
}
} else {
for (let project of this.projects) {
// TODO:
}
}
}
If no one knows a solution for me, I already know how I could do it in another way, but I would like to do it like this...
Gracias, guys.
Upvotes: 2
Views: 144
Reputation: 976
This is because when you store the getRequirements
method in the func
variable, you separate it from its context.
You have to reattach again the this
context to func
.
You just have to call the func
function like this:
func.call(this); // call func with this as context
func(); // call func with undefined context
func.call({}); // call func with empty object as context
This way, you force calling func
with this
as context.
You have to bind
a new context before calling the function:
func(); // call func with undefined context
func = func.bind(this);
func(); // call func with this as context
func(); // recall func with this as context
This way, you link this
as new context for func
.
Upvotes: 4
Reputation: 149040
Look at this line
let func = this[`get${type}`];
It unbinds (or 'disconnects') the function from the this
reference to the class so that when you call func()
, this
becomes undefined
.
There are a couple ways to get around this. You could re-bind this
using bind
, like this:
let func = this[`get${type}`].bind(this);
Or you could explicitly rebind the methods within the constructor:
class Project {
constructor(project, api) {
...
this.getTasks = this.getTasks.bind(this);
this.getRequirements = this.getRequirements.bind(this);
this.getReleases = this.getReleases.bind(this);
}
}
Or you could define your methods as lambda expression properties, like this:
class Project {
data = {};
getTasks = () => { ... };
getRequirements = () => { ... };
getReleases = () => { ... };
}
These are not the only solutions, of course, and they may have some different side-effects. For example, the lambda expression properties are enumerable, so they will appear in Object.keys(new Project())
.
Upvotes: 4