Platform: Selectors: filter undefined values

Created on 30 Apr 2018  路  5Comments  路  Source: ngrx/platform

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[x] Feature request
[ ] Documentation issue or request

What is the current behavior?

I created a repro / example:
https://stackblitz.com/edit/angular-ngrx-effects-1rj88y

Let's look at the following selectors:

export const selectFoo = createFeatureSelector<State>('foo');

export const selectFooBar = createSelector(selectFoo, state => state.bar);

export const selectFooFoobar = createSelector(selectFoo, state => state.foobar);

export const selectProjectedValues = createSelector(
  selectFooBar,
  selectFooFoobar,
  (foo, foobar) => {
    if (foo && foobar) {
      return { foo, foobar };
    }

    // XX: Is it possible to filter this undefined value in the selector?
    return undefined;
  }
);

selectProjectedValues will emit an undefined value if foo or foobar have an undefined value.

Filtering the projected undefined value would need to happen in the subscribor, e.g.

store
  .select(selectProjectedValues)
  .pipe(filter(value => !!value))

Expected behavior:

A projected value from foo and foobar should be returned, if both states have a defined value. Let's pretend we have a list and an activeItemId, an active item will be emitted if both the list and the identifier are set. If one of them is undefined, there's no active item.

The question or feature request is: is it possible to filter the undefined value in terms of the selectProjectedValues API?

Meaning that store.select(selectProjectedValues) will never emit an undefined value.

Minimal reproduction of the problem with instructions:

See above.

Version of affected browser(s),operating system(s), npm, node and ngrx:

[email protected]

Other information:

Accepting PRs Docs Store

Most helpful comment

The expected behaviour is achieved by either:

store.pipe(
  map(state => selectProjectedValues(state)),
  filter(val => !!val)
)

or alternatively:

export const selectProjectedValuesFiltered = pipe(
  map(state => selectProjectedValues(state)),
  filter(val => !!val)
);

store.pipe(selectProjectedValuesFiltered)

With the current implementation, store.select(something) is an alias for store.pipe(map(state => something(state)).


This issue could also be a documentation request on "Composing a read model" / "Writing a selector API"

All 5 comments

One way could be to make selectors become pipeable operators :question:

export const selectSomething = pipe(
  selectOne,
  selectTwo,
  map(() => /*..*/),
  filter(/*..*/ )
);

???

I don't think this is possible with the API, and also not wanted. Others may want undefined values to be emitted. Also the select method explicitely is there for emitting every update of the state. I think the way you show it with pipe(filter) is the way to go.

The expected behaviour is achieved by either:

store.pipe(
  map(state => selectProjectedValues(state)),
  filter(val => !!val)
)

or alternatively:

export const selectProjectedValuesFiltered = pipe(
  map(state => selectProjectedValues(state)),
  filter(val => !!val)
);

store.pipe(selectProjectedValuesFiltered)

With the current implementation, store.select(something) is an alias for store.pipe(map(state => something(state)).


This issue could also be a documentation request on "Composing a read model" / "Writing a selector API"

I think this would be better served as an addition to the docs. Would you be able to write something up @dherges?

@brandonroberts I've started a little blog post series, pt. 1 on read and write models

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sandangel picture sandangel  路  3Comments

alvipeo picture alvipeo  路  3Comments

NathanWalker picture NathanWalker  路  3Comments

gperdomor picture gperdomor  路  3Comments

hccampos picture hccampos  路  3Comments