[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
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))
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.
See above.
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
Most helpful comment
The expected behaviour is achieved by either:
or alternatively:
With the current implementation,
store.select(something)is an alias forstore.pipe(map(state => something(state)).This issue could also be a documentation request on "Composing a read model" / "Writing a selector API"