Dynamic @Selector with NGXS Facades pattern

Viewed 480

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.

  1. 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.

  2. 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!

0 Answers
Related