Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

219
Views
How do I make a component wait for async data from service

A service is fetching api data and I need to keep and use it in many other components every time the url changes (router links) without calling api again. Api should fetch only when the service runs.

I need to make the component method wait until data is available.

(Real code reduced to minimum for readability)

Service

  constructor(private http: HttpClient) {
    this.fetchData();
  }

  fetchData(): void {
    this.http.get(this.endpointUrl).subscribe((res)=>{
      this.data = res
    });
  }

  getData(selectedCategory): DataType {
    return this.data.find(cat => cat === selectedCategory)
  }

Component

  ngOnInit(): void {
    this.activatedRoute.paramMap.subscribe(
      (params: ParamMap) => {
        // I need params before calling service method
        // this method must wait until the "data" is available in service.
        this.selectedCategory = this.service.getData(params.category);
      }
    );
  }
about 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Without many changes, it would be possible to subscribe to fetchData() which instead returns an observable transporting requested data. We use tap for the side effect of also setting this.data in the Service. Don't forget to unsubscribe()! Also mind some syntax errors, I didn't check for them. Suggesting to add typings for <any>.

  fetchData(): Observable<any>{
   return this.http.get(this.endpointUrl).pipe(
      tap(res => this.data = res),
      catchError(console.log(err))
    )
  }
  ngOnInit(): void {
    this.activatedRoute.paramMap.subscribe(
      (params: ParamMap) => {
        this.myService.fetchData().subscribe(res => {
        this.selectedCategory = this.service.getData(params.category);
        // Or use
        // this.selectedCategory = this.res.find(cat => cat === params.category)
         });  
      }
    );
  }

Subscribe in service

Though subscribing in service is not advised (especially onRoot Service) because the service will do a request every time url changes, but I guess this is what you want. So be warned.

We subscribe to param changes in constructor. Service will request new data on each route change. Queried data will be emitted using BehaviourSubject which retains and updates data. Components can subscribe to BehaviourSubject instead using | async pipe or manual subscription.

Service:

let data = new BehaviorSubject(null); 

constructor() {
    this.activatedRoute.paramMap.subscribe(
      (params: ParamMap) => {
        this.fetchData().subscribe(res => {
           this.data.next(res);
         });  
      }
    );
  }
about 4 years ago · Santiago Trujillo Report

0

I would suggest using the async pipe (if you need to display the data) and you should avoid nesting subscriptions.

For data persistence over page refresh, you'll need to use the local storage or the session storage. I'm not a big fan of this, but I guess it depends on your requirements.

You can manage your state with the help of a BehaviourSubject, but if you want to do more complicated stuff and to keep your code clean, I'll recommend using a state management library like @ngrx/component-store .

Your service

private readonly _state = newBehaviourSubject<Record<string, DataType>>(JSON.parse(localStore.getItem('state')) ?? {});
readonly state$ = this._state.asObservable();


getData(category: string) {
        return of(category).pipe(
            withLatestFrom(this.state$), // you don't want to do something like this.state.pipe(...) because you'll resubscribe to it multiple times because the implementation below
            switchMap(([key, data]) => {
                    if (key in data) return of(data[key]); // return the found category

                    return this.http.get(this.endpointUrl).pipe(
                        tap(res => {
                            const updatedData = { ...data, [key]: res };
                            this._state.next(updatedData); // update your state
                            localStorage.setItem('state', JSON.stringify(updatedData) // update local storage
                        })
                    );
                }
            )
    }

Component

readonly selectedCategory$ = this.activatedRoute.paramMap.pipe(
   map(paramMap => paramMap.get('category')), // I assume that you expect a string
   filter(category => !!category) // it makes sure that the result is not null or undefined
   switchMap(category => this.service.getData(category)),
   catchError(error => {...}), // handle your errors
   filter(res => !!res) // if you want to make sure the response is not null
)

about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!