0

I would like to make two treatments on a same api call data.

I have a first effect:

loadSchedulings$ = createEffect(() =>
  this.actions$.pipe(
    ofType(ESchedulesActions.GetSchedulesByDate),
    mergeMap(() =>
      this.apiCallsService.getSchedulings().pipe(
        map(trips => ({ type: ESchedulesActions.GetSchedulesByDateSuccess, payload: trips })),
        catchError(() => EMPTY)
      )
    )
  )
);

I call getSchedulings service method which make an api call then a treatment 1 on data is done

ApiCallsService :

getSchedulings() {
  return this.http.get<ISchedules>(this.SchedulingByDateLocal2).pipe(
      ...
      return groupByDate;
    })
  );
}

I would like to make a second treatment on the same data source. (raw data got from api ) but in parallel of the first because they are independent

So by logic I create a second effect

loadDirections$ = createEffect(() =>
  this.actions$.pipe(
    ofType(ESchedulesActions.GetSchedulesByDate),
    mergeMap(() =>
      this.apiCallsService.getDirections().pipe(
        map(trips => ({ type: ESchedulesActions.GetDirectionsByDateSuccess, payload: directions})),
        catchError(() => EMPTY)
      )
    )
  )
);

Then in apiCallService I should have a method

getDirections() {
  return this.http.get<ISchedules>(this.SchedulingByDateLocal2).pipe(
      ...
      return groupByDirections;
    })
  );
}

The problem here is that I will have two requests for the same data.

To summarize the actual workflow :

LoadSchedulings ( effect ) ==> loadSchedulings ( service ) ==> API Call ==> treatment 1 LoadDirections ( effect ) ==> loadDirections ( service ) ==>(Same) API Call ==> treatment 2

So I would like to only use the first api request's data for two treatments

Update: According to the response of Manuel Panizzo I should have something like this ?

getRawData() {
  return this.http.get<ISchedules>(this.SchedulingByDateLocal2)
}

Effect.ts

loadSchedulings$ = createEffect(() =>
  this.actions$.pipe(
    ofType(ESchedulesActions.getRawData),
    pipe((data) =>
      this.apiCallsService.getSchedulings(data).pipe(
        map(trips => ({ type: ESchedulesActions.GetSchedulesByDateSuccess, payload: trips })),
        catchError(() => EMPTY)
      )
    ),
    pipe((data) =>
      this.apiCallsService.getDirections(data).pipe(
        map(directions=> ({ type: ESchedulesActions.GetDirectionsByDateSuccess, payload: directions})),
        catchError(() => EMPTY)
      )
    ),
  )
);

2 Answers 2

1

I think you could also dispatch a getRawDataSuccess action (that performs 1 api call)

getRawData$ = createEffect(() =>
  this.actions$.pipe(
    ofType(ESchedulesActions.getRawData),
    mergeMap(() =>
      this.apiCallsService.getRawData().pipe(
        map(data => ({ type: ESchedulesActions.GetRawDataSuccess, payload: data })),
        catchError(err => ({ type: ESchedulesActions.GetRawDataError, payload: err }))
      )
    )
  )
);

Then create one effect per treatment listening for getRawDataSuccess action:

getSchedulesByDate$ = createEffect(() =>
  this.actions$.pipe(
    ofType(ESchedulesActions.getRawDataSuccess),
    map((action) => {
      return {
        type: ESchedulesActions.GetSchedulesByDateSuccess,
        payload: action.payload.schedulesByDate,
      }
    })
  )
);

getDirectionsByDate$ = createEffect(() =>
  this.actions$.pipe(
    ofType(ESchedulesActions.getRawDataSuccess),
    map((action) => {
      return {
        type: ESchedulesActions.GetDirectionsByDateSuccess,
        payload: action.payload.directionsByDate,
      }
    })
  )
);

This would be cleaner IMO and will theoretically run in parallel too.

Sign up to request clarification or add additional context in comments.

4 Comments

I don't see where you trigger getDirections from row data and get schedulings treatments ?
maybe this code is more "beautiful" but two effects dispatching two actions have the same result that one effect dispatching two actions.
@infodev the treatments are done in the last two effects of this code snippet, directions' treatments are done in the last effect within the map operator where I assigned payload: action.payload.directionsByDate where I'm guessing that the api response has a directionsByDate property, but if that's not the case then there is where you need to write your custom code to craft the directions by date. the important thing is that you have the raw api response in action.payload prop so you can do whatever you want with it.
OK I understand better. In every treatment I should transform apiRawDatato data by direction and by date , it's not a property but a transformation of apiRawData. so I will add my logic just before returning the last effect
1

use only one effect to get the raw data from the API and put in your store then create two diferents selectors that aply your groupByDirections and groupByDate logic.

Or extract the groupByDirections and groupByDate logic to the effect. an make a pipe in your effect that aply both logics and dispatch two actions in the same effect

UPDATE:

if you want execute two actions try this:

  loadSchedulings$ = createEffect(() =>
    this.actions$.pipe(
      ofType(ESchedulesActions.getRawData),
      mergeMap(action => this.apiCallsService.getRawData()),
      map(rawApiData => {
        const groupByDate = {}; // do your logic with rawApiData
        const groupByDirections = {}; // do your logic with rawApiData
        return { groupByDate, groupByDirections };
      }),
      mergeMap(groupedData => [
        {
          type: ESchedulesActions.GetDirectionsByDateSuccess,
          payload: groupedData.groupByDirections,
        },
        {
          type: ESchedulesActions.GetSchedulesByDateSuccess,
          payload: groupedData.groupByDate,
        },
      ]),
    ),
  );

8 Comments

I have updated my question, can you give me your feedback ?
is the treatments async ?
i dont understand waht do you mean with treatments async?
@ManuelPanizzo I think last operator in your code will fail because mergeMap expects to return an inner observable, not an array.
when you dont return a inner observable from mergeMap operator the operator make a obserbable from te returned non observable value. if you subscribe to that observable you get two emmisions one for each element of array. see: stackblitz.com/edit/angular-gxglcx
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.