Search code examples
angularngrx

How can I access my Store from a service?


I use NgRx recently with effects to manage send API requests. My API requests are in a service and my effect uses this service. Very classic.

@Injectable({
  providedIn: 'root'
})
export class MaterialService {
  private url = "materials";

  constructor(private http: HttpClient) { }

  getMaterials () {
    return this.http.get (this.url).pipe (
      catchError (this.handleError)
    );
  }

  handleError (error: HttpErrorResponse): Observable<never> {
    return throwError (error.message);
  }
}
@Injectable()
export class MaterialEffects {

  @Effect() loadMaterial$ = this.dataPersistence.fetch(
    MaterialActionTypes.LoadMaterial,
    {
      run: (action: LoadMaterial, state: MaterialPartialState) => {

        return this.materialService.getMaterials ().pipe (
          map (data => {
            return new MaterialLoaded(data);
          }),
//          catchError (error => of (new MaterialLoadError (error)))
        );
      },

      onError: (action: LoadMaterial, error) => {
        console.error('Error', error);
        return new MaterialLoadError(error);
      }
    }
  );
...

Overall it works great. I just love it :)

But for certain requests, I need to recover some ID to create my URL. These IDs are mostly generic IDs. For example the ID of our client. https://my.example.com/perimeters/[PERIMETER_ID]/relationships/users

How can I use my service to retrieve my content ID from my store, create my URL and return my Observable as expected?

thank you in advance


Solution

  • Inject the store into your effects class MaterialEffects, and get the value you need, then pass that as a parameter into your MaterialService.

    So your effect would look like:

    @Injectable()
    export class MaterialEffects {
    
        constructor(private store: Store<any>)
    
        @Effect() loadMaterial$ = this.dataPersistence.fetch(
            MaterialActionTypes.LoadMaterial,
            {
                run: (action: LoadMaterial, state: MaterialPartialState) => {
    
                    return this.store.pipe(
                        select(x => x.perimiterId),
                        mergeMap((perimiterId) => {
                            materialService.getMaterials(perimiterId).pipe(
                                map(data => {
                                    return new MaterialLoaded(data);
                                }),
                                // catchError (error => of (new MaterialLoadError (error)))
                            )
                        })
                    )
                },
    
                onError: (action: LoadMaterial, error) => {
                    console.error('Error', error);
                    return new MaterialLoadError(error);
                }
            }
        );
    ...