[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
The entity adapter is great for managing a list of ng-components of the same type (like a list of users). Currently you can get some nice selectors out of the box:
// user.reducer.ts
...
export const {
// select the array of user ids
selectIds: selectUserIds,
// select the dictionary of user entities
selectEntities: selectUserEntities,
// select the array of users
selectAll: selectAllUsers,
// select the total user count
selectTotal: selectUserTotal,
} = adapter.getSelectors();
Unfortunately, I very often need to select just one entity by its id (that never changes). A naive implementation of this requirement would be:
// user.container.ts
...
this.user$ = this.store$.pipe(select(fromUser.selectUserEntities))
.pipe(
map((entities: { [id: string]: User}) => {
return entities[this.idOfUserIWantToSelect];
}),
);
But in this case this.user$ is updated every time anything changes in any entity (not only the one I'm interested in). If this.user$ is passed using async pipe, this implies a useless refreshing of the ui in all user-dummy-components.
The solution (at least in my case) is to use something like this:
// user.reducer.ts
...
export const getEntityById = (id: string) => (state: State) => state.entities[id];
export const getUserEntityById = (id: string) => createSelector(getUserState, getEntityById(id));
// user.container.ts
...
// idOfUserIWantToSelect never changes
this.user$ = this.store$.pipe(select(fromUser.getUserEntityById(idOfUserIWantToSelect)));
This way the selector is correctly memoized. I think it would be very helpful to have something ready out the box that devs can use to avoid writing the same code over and over.
This is a simple demo that illustrates the two behaviors described above.
ngrx-adapter-multi-comp
[ ] Yes (Assistance is provided if you need help submitting a pull request)
[ ] No
Hey @mauriziocescon, really like that idea. I have implemented this selector over and over again for several entities/projects.
I made a quick implementation, lets discuss if it makes sense or not. Any other thoughts?
I think with the introduction of createselector with props and ngrx 6.1 (I think #1175 ), this issue can be closed: it seems to me it is working fine!
// user.reducer.ts
...
export const {
// select the array of user ids
selectIds: selectUserIds,
// select the dictionary of user entities
selectEntities: selectUserEntities,
// select the array of users
selectAll: selectAllUsers,
// select the total user count
selectTotal: selectUserTotal,
} = adapter.getSelectors();
export const getUserState = createFeatureSelector<UserState>('users');
export const getUserEntities = createSelector(getUserState, selectUserEntities);
export const getUserEntityById = () => {
return createSelector(
getUserEntities,
(entities: Dictionary<User>, props: { id: string }) => {
return entities[props.id];
},
);
};
Here is the demo above with the new functionalities
new-ngrx-adapter-multi-comp
Great job, thanks!
Ok, I'm glad you like it 馃槃 ; I'll close this issue and the according PR.
Most helpful comment
I think with the introduction of createselector with props and ngrx 6.1 (I think #1175 ), this issue can be closed: it seems to me it is working fine!