I have the following structure:
state:
@Selector()
static getClientById(state: ClientListStateModel) {
return (id: number) => state.clientList.find(f => f.id === id);
}
facade (storeService):
@Select(ClientListState.getClients) clients$: Observable<ClientModel[]>;
@Dispatch()
getClientList() {
return new GetClientList();
}
component:
this.storeService.getClientById(clientId).subscribe(result => this.client = result)
The idea is that in main (clientList) page I dispatch an action that loads all clients,
this.storeService.getClientList();
and afterwards in details page I want to be able to dynamically select a client by id from the activatedRoute and show all client details data (without making a new call to the backend, just selecting a slice of state).
If it wasn't for facade (storeService), I could inject @Select directly in component and use a dynamic clientId like for e.g.:
@Select(ClientListState.getClientById(this.clientId)) client$: Observable<ClientModel>;
private clientId;
ngOnInit() {
this.clientId = this.route.get('id')
}
I can't use the same approach in facade (storeService) as I don't have reference to clientId, and it's really dirty to somehow inject it there.
What I came up with is reading through documentation and using dynamic selector (https://www.ngxs.io/concepts/select):
facade (storeService):
@Select(ClientListState.getClients) clients$: Observable<ClientModel[]>;
constructor(private store: Store) {
}
getClientById(id): Observable<ClientModel> {
return this.store.select(ClientListState.getClientById(id));
}
@Dispatch()
getClientList() {
return new GetClientList();
}
state:
// DynamicSelector
static getClientById(id: keyof ClientListStateModel) {
return createSelector([ClientListState], (state) => {
return state.clientList.find(c => c.id === id);
});
}
and finally in component
this.storeService.getClientById(this.clientId);
While this is working, somehow I am not really sure if this is the cleanest solution.
First of all I don't like that in facade I am forced to inject store (as this is one of the main reasons why @SelectSnapshot and @Dispatch decorators were added in ngxs-labs) to eliminate store from constructor.
I really searched a lot but couldn't find... Do we have a possibility to create a dynamic Selector by somehow injecting a function e.g: @Select((id) => SomeState.getSomeDataById(id)) and somehow passing Id through @Selector?
This is more of an open question / discussion. I believe there are still people out there that are having the same questions. Thank you!