-1

I am currently using Angular 9 and I am having some issues with accessing a global variable. I can access the listOfProjects variable when I pass an ES6 callback function to map but when I use a normal function I get an error saying that Cannot read property 'push' of undefined. I think that the variable has gone out of scope. I am little bit lost regarding how to fix this. Also if you see any bad practices in my code please feel free to point them out as well as I am fairly new to angular.

The code with the normal function:

export class DataService {

  listOfProjects: Project[] = [];
  API_URL: string = "API_URL";
  homePageHeading: string; 

  constructor(private httpClient: HttpClient) { }

  getProjects() {
    this.listOfProjects.length = 0;

    this.httpClient.get<any[]>("API_URL").pipe(
    
    
    map(function mapData(res) {
      this.homePageHeading = res[0].heading

      res[0].projects.map( (project) =>  
            this.listOfProjects.push(
            { 
              "company": project.company,
              "description": project.description,
              "imageUrl": this.API_URL + project.image[0].url,
              "Link": project.Link
            }) 
          )
    })     
    ).subscribe(res => {
      console.log(this.listOfProjects);
    });
  }
}

The code with the normal function:

export class DataService {

  listOfProjects: Project[] = [];
  API_URL: string = "API_URL";
  homePageHeading: string; 

  constructor(private httpClient: HttpClient) { }

  getProjects() {
    this.listOfProjects.length = 0;

    this.httpClient.get<any[]>("API_URL").pipe(
    
    
    map((res) => {
      this.homePageHeading = res[0].heading

      res[0].projects.map( (project) =>  
            this.listOfProjects.push(
            { 
              "company": project.company,
              "description": project.description,
              "imageUrl": this.API_URL + project.image[0].url,
              "Link": project.Link
            }) 
          )
    })     
    ).subscribe(res => {
      console.log(this.listOfProjects);
    });
  }
}
jame_smith
  • 23
  • 4
  • 1
    Classic javascript `function`s define their own `this` context. If you specifically want to use normal function here, you can save outer `this` into a variable (like `this_`) before calling `map`. But I would advise just using context-free callback instead. – comonadd Dec 13 '20 at 21:09
  • 1
    Have a look at this question https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback – Gunnar B. Dec 13 '20 at 21:10
  • 1
    you may want to use tap instead of map and inside of the function of tap, do the work you were trying to do with the res.projects.map. – Dream_Cap Dec 13 '20 at 21:15
  • @dmitryguzeev where about would you declare it? Because I am having an issue where I can't declare the variable inside of `getProjects` but I can declare it inside the `map` function. – jame_smith Dec 13 '20 at 21:32
  • Does this answer your question? [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – R. Richards Dec 13 '20 at 21:35
  • @R.Richards I read through that and I understand what's going on now. But I am having an issue where I can't declare a variable with the `this` inside `getProjects()` but I can declare one inside the `map` function. – jame_smith Dec 13 '20 at 21:40

1 Answers1

2

When you use a classic function the value of this is determined by how a function is called. It more or less looks at the object that is calling it to determine what is this.

Arrow functions look at the outer scope of the function to determine what this is.

So in your case, you want this to be the outer scope, meaning the DataService. So using arrow function ignores the object that is calling the function, but looking at where the function was defined for scope.

You can read more here for examples.

toms
  • 515
  • 6
  • 23