mr__brainwash
mr__brainwash

Reputation: 1382

Effect using withLatestFrom called it even ofType(action) was not fired

I am using Angular 5, ngrx/store. I have an effect:

@Effect()
  updateAfterChanges$ = this.actions$.pipe(
    ofType(ActionTypes.ChangesInItems),
    withLatestFrom(
      this.store.select(fromReducers.getItemsList)
    ),
    switchMap(([action, itemsList]: [ActionType, Items[]]) => {
       return [new UpdateItems()]
    })
)

getItemsList looks like this:

export const getItemsList= createSelector(
  fromAnotherReducer.getAllItems,
  getCurerntItemdId,
  (allItems, itemId) => collectItems(allItems, allItems[itemId].subItems)
);

This selector called on absolutely another page - page1. Where i don't have items at all. Items are loaded from the server when i open model window on page2. So on the page1 i am getting an error Cannot read property 'subItems' of undefined. Why this selector even called not after ofType(ActionTypes.ChangesInItems)? I must add a check in selector:

Object.keys(allItems).length !== 0 ?
    collectItems(allItems, allItems[itemId].subItems) : []

Why is this happening? I don't want to add checks in every selector that uses dynamically loaded data. I expect that effect will be called only in response to ofType(ActionTypes.ChangesInItems)

Upvotes: 4

Views: 1602

Answers (2)

sarea
sarea

Reputation: 225

This is an expected behaviour, it's how withLatestFrom works, so it will start listening to the given observable immediately, but it will only emit the value when source get emitted!

This example will explain what’s happening:

So the console.log inside test() will shown immediately but the returned value from test() will only shown when the click event triggered

Upvotes: 0

bc1105
bc1105

Reputation: 1270

As you use it here, withLatestFrom will always be executed. You don't need logic to check for items, tweak your structure a bit:

@Effect()
updateAfterChanges$ = this.actions$.pipe(
  ofType(ActionTypes.ChangesInItems),
  switchMap(action => {
    return this.store.pipe(
      select(fromReducers.getItemsList),
      map(items => {
        return [new UpdateItems()]
      }),
    );
  }),
)

Upvotes: 1

Related Questions