Search code examples
angulartypescriptfirebase-realtime-databaserxjsngoninit

Angular NgOnInit executing method before another


I have an angular application where I am trying to get an array of sources for an image carousel. How I have it set up currently I have a "getUrls()" method to get the urls from the database like so

http.service.ts:

getUrls() {
    this.http
      .get<string[]>(
        '<DATABASE_LINK>'
      )
      .subscribe((imageUrls: string[]) => {
        this.carouselService.setUrls(imageUrls);
      });
  }

That method calls the method "setUrls" to set them into an array stored in a service

carousel.service.ts:

  urls: string[] = [];

  constructor() {}

  setUrls(urls: string[] | []) {
    this.urls = urls || [];
    debugger;
  }

  getImages() {
    debugger;
    return this.urls;
  }

Then inside of the carousel component I call both of the previous methods in ngOnInit

image-carousel.component.ts:

  ngOnInit(): void {
    this.httpService.getUrls();
    this.images = this.cService.getImages();
  }

This would then assign the values set by the "setUrls()" method, but for some reason, it is reaching the "getImages()" method before setting the Urls.

I got it to work by taking the "getImages()" line into a separate method and clicking a button to call it, so that I could make sure that everything worked in the right order and it did, however I want it to do all of that when the components are initialized.

I am sure I am missing something, so anything helps, even if I have to refactor a lot.

I tried to use a ".pipe(tap()" in the "getUrls()" method instead of a subscribe, however it would never call the "setUrls()" method.


Solution

  • As getUrls() performing a asynchronous task which is http.get,you have to wait to get images until asynchronous task gets completed.

    So one of the possible solution could be,you can return observable from your http.service.ts service and inside component ngOnInit you can fetch images inside subscription.

    http.service.ts:

    getUrls() {
        return this.http
          .get<string[]>(
            '<DATABASE_LINK>'
          )
          .pipe(
             map((imageUrls: string[]) => {
                this.carouselService.setUrls(imageUrls);
             })  
           );
      }
    

    carousel.service.ts:

      urls: string[] = [];
    
      constructor() {}
    
      setUrls(urls: string[] | []) {
        this.urls = urls || [];
        debugger;
      }
    
      getImages() {
        debugger;
        return this.urls;
      }
    

    image-carousel.component.ts:

    ngOnInit(): void {
        this.httpService
            .getUrls()
            .subscribe(
              () => {
                 this.images = this.cService.getImages();
              }
            );
      }