Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

216
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda