0

I've got an Angular (v12) service, holding API calls through httpClient requests, where I also would like to put a method to check if an object already exists at backend level (before it reaches it, but of course there also is a safety there).

So what I do is trigger the http get, then pass the answer to a method to enrich it and store the result in a private attribute (visaDatesList) which is supposed to hold the list of my objects.

That list is being fed while my component calls the getAllVisaDates() method, which I was able to confirm using a console.log...

Below, part of my service's code:

@Injectable({
  providedIn: 'root'
})
export class VisasService{
  private visaDatesList: VisaDate[] = [];

  constructor(private httpClient: HttpClient) {}

  public getAllVisaDates(): Observable<VisaDateAnswer> {
    return this.httpClient
      .get(`${this.baseUrl}/visa-dates`, { observe: 'response' })
      .pipe(map(this.getVisaDates));
  }

  public checkIfVisaDoesNotAlreadyExists(visa: VisaDate): boolean {
    console.log(this.visaDatesList);
    let matchedYear = false;
    let matchedMonth = false;
    for (const entry of this.visaDatesList) {
      for (const [key, value] of Object.entries(visa)) {
        if (key === 'visaYear' && value === visa.visaYear) {
          matchedYear = true;
        }
        if (key === 'visaMonth' && value === visa.visaMonth) {
          matchedMonth = true;
        }
        if (matchedMonth && matchedYear) {
          return false;
        }
      }
      matchedYear = false;
      matchedMonth = false;
    }
    return true;
  }

  private getVisaDates(res: HttpResponse<VisaDate[]>) {
    const header = res.headers.get('x-visaapp-params');
    const data = res.body;
    this.visaDatesList = res.body as VisaDate[];
    return { size: header, data, status: res.status };
  }
}

As I said, the point here, in my getVisaDates() method, using a console.log, I can see that my list visaDatesList is properly fed.

Problem lies in the checkIfVisaDoesNotAlreadyExists() method. For some reason the list is seen as empty when another component calls the service, even if my previous console.log (in the getVisaDates()) was showing datas... If I'm not wrong, services are supposed to be Singletons, and storing data to be shared between components is supposed to be the proper way of using them ?

Maybe I am missing something obvious here but I can't have this working, any idea/help ?

Thanks!

PriPri
  • 3
  • 4
  • 1
    How did you defined the service? In the `module.ts`, do you have it in `provider: [VisasService]`? In your 'component`, do you have it in the annotation `@Component` or in the `constructor`? You should take a look at https://stackoverflow.com/questions/53571546/angular-7-shared-service-is-not-shared – Pilpo Nov 23 '21 at 09:54
  • In the component are you provideing the service in the component provider, if so they will not be singleton – vaira Nov 23 '21 at 10:00
  • @Pilpo : Yes my components have the Component decorator, I'm injecting the service in each components' constructor, as constructor(private visaService: VisasService), I believe this is working fine but thanks for pointing this eventuality! – PriPri Nov 23 '21 at 10:13
  • @vaira: true! I had this in mind and just the injection, as explained above, but thanks for your suggestion – PriPri Nov 23 '21 at 10:13

1 Answers1

1

You're losing the context of this keyword in getVisaDates() since it's passed as a callback with it's own scope. So when you're attempting this.visaDatesList = res.body as VisaDate[]; it isn't necessarily assigning the value to the class member variable visaDatesList.

You'd either need to use bind(this)

return this.httpClient
  .get(`${this.baseUrl}/visa-dates`, { observe: 'response' })
  .pipe(map(this.getVisaDates.bind(this)));

Or use arrow function

return this.httpClient
  .get(`${this.baseUrl}/visa-dates`, { observe: 'response' })
  .pipe(map((res: HttpResponse<VisaDate[]>) => this.getVisaDates(res)));

You could find more info about using this keyword in callbacks here.

ruth
  • 29,535
  • 4
  • 30
  • 57
  • I believe I still have a lot to learn with Angular, many thanks for your answer, I got to thoroughly read the message you linked, the binding did the trick, but using an arrow seems also relevant, in any case my problem is solved, so once again, many thanks! – PriPri Nov 23 '21 at 10:16