How Can I Access a Service in my Angular NGRX Selector
Asked Answered
S

2

12

In my Angular app I have a Selector file plan.selectors.ts which has a few really complex Selectors. A lot of calculations are carried out when retrieving the data and some of these calculations are shared with business logic elsewhere in the application. Take a trivial example, I have a DateService which uses the Moment library and it provides functions to the application like getDatePlusHours where I can pass in a Date and a number of hours and it returns the new Date. I want to be able to use this function from my DateService in my Selector but I just cannot figure a way to do this as I can't see how to inject the Service in.

A simplified plan.selectors.ts looks like this with what I am trying to do:

import { createFeatureSelector, createSelector } from '@ngrx/store';

const getPlanFeatureState = createFeatureSelector<PlanState>('plan');

export const getStartDate = createSelector(
  state => state.startDate
);

export const getDuration = createSelector(
  state => state.duration
);

export const getEndDate = createSelector(
  getStartDate,
  getDuration,
  (startDate, duration) => {
    return dateService(startDate, duration);
  }
);

I'm trying to prevent duplicating huge amounts of Service functions into my Selector file. Any advice really welcome.

Sevastopol answered 3/10, 2020 at 19:21 Comment(1)
I think the pattern to use here is to call the service from wherever you are subscribing to the store, then pass the result as arguments to the selector.Jackquelin
G
0

The best practice in NGRX is that the selector only reads and sends a portion of the state, ie it does not perform any calculations or external services calls . The calculations performing in the Reducer, and the external services calling in the Effect. Here you can see an good example with full descripting. Let me know if you need more details.

Geezer answered 18/11, 2022 at 15:39 Comment(0)
R
0

I didn’t have a chance to implement it in rxjs, but I had a similar problem in redux which I solved using an unconventional usage of actions.

The code in rxjs should look something like that:

// Dispatching with callback
const startDate = this.store.select(getStartDate);
const duration = this.store.select(getDuration);

this.store.dispatch(getDateDiff({ startData, duration, (result) => {
  console.log(result);
}});

// Effect:
getEndDate = createEffect(() => {
  return this.actions.pipe(
    ofType(GET_END_DATE),
    switchMap((action: any) => {
      return this.dateService.getEndDate(action.startDate, action.duration)
        .pipe(
          map((result) => ({ endDate: result })),
          catchError((err: Error) => of(new DateDiffError(err)),
          do(result => action.cb(result))
        ),
     ); 
    }),  
  )
}

I think you can probably use the selector inside the effect.

Rictus answered 28/7, 2024 at 17:17 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.