Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

218
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda