I am working on a angular 11 and NGRX 11 project. I wish to have 2 inputs select which are users but of different user type.
For example :
I have 2 types of user (Seller and Buyer) :
I use NGRX and I have a store User but when I call the store I return the same list of user.
How I can detach the list of user seller and list of user buyer ? (2 stores ? 2 selectors ? 2 vesions of the store ?)
user.action.ts
export const loadUsers = createAction(
'[Users List] Load Users via Service',
props<{ filters: UserFilter }>()
);
export const usersLoadedDone = createAction(
'[Users Effect] Users Loaded Successfully',
props<{ users: Page<User> }>()
export const loadUser = createAction(
'[Users List] Load User via Service',
props<{ userId: string }>()
);
export const createUser = createAction(
'[Create User Component] Create User',
props<{ event: any, user: User }>()
);
export const deleteUser = createAction(
'[Users List Operations] Delete User',
props<{ userId: string }>()
);
export const updateUser = createAction(
'[Users List Operations] Update User',
props<{ user: User }>()
);
export const userActionTypes = {
loadUsers,
usersLoadedDone,
loadUser,
createUser,
deleteUser,
updateUser,
};
user.reducers.ts
export interface UserState extends EntityState<User> {
isLoading: boolean;
totalElements: number;
totalPages: number;
empty: boolean;
page: number;
filters: UserFilter;
}
export const adapter: EntityAdapter<User> = createEntityAdapter<User>({
selectId: user => user.userId
});
export const initialState = adapter.getInitialState({
isLoading: false,
totalElements: null,
totalPages: null,
page: 0,
empty: true
});
export const userReducer = createReducer(
initialState,
on(userActionTypes.loadUsers, (state, res) => ({
...state,
isLoadingList: true,
filters: res.filters
})),
on(userActionTypes.usersLoadedDone, (state, action) => {
return adapter.setAll(
action.users['content'],
{
...state,
isLoadingList: false,
isLoad: true,
totalElements: action.users.totalElements,
totalPages: action.users.totalPages,
empty: action.users.empty,
page: action.users.number,
}
);
}),
...
);
export const {selectAll, selectIds} = adapter.getSelectors();
user.selectors.ts
export const userFeatureSelector = createFeatureSelector<UserState>('users');
export const getAllUsers = createSelector(
userFeatureSelector,
selectAll
);
...
ps : As you can see the list of users is paginated so my angular application only has part of the data
You can detach each user by having two different states in a feature state:
export interface IUsersFeatureState{
userSeller: IUserSellerState;
userBuyer: IUserBuyerState;
}
Then you can have 2 different reducer for each:
export const reducers: ActionReducerMap<IUsersFeatureState> = {
userSeller: UserSellerReducer,
userBuyer: UserBuyerReducer
}
Each reducer, you can have different actions to both load the userSeller and userBuyer:
export interface IUserSellerState {
loaded: boolean,
loading: boolean,
userSeller: UserSellerModel
}
export interface IUserBuyerState{
loaded: boolean,
loading: boolean,
userBuyer: UserBuyerModel
}
export const initialState: IUserSellerState ={
loaded: false,
loading: false,
userSeller: null
}
on(userSellerActionTypes.loadSellerUsers, (state, res) => ({
...state,
loaded: false,
loading: true
userSeller: res
})),
on(userBuyerActionTypes.loadBuyerUsers, (state, res) => ({
...state,
loaded: false,
loading: true
userBuyer: res
})),
You can control the fetch from the API via Effects class as well. For the store module, you can register the reducer like below:
StoreModule.forFeature('UsersFeature', reducers),
For the selectors, you can have 2 selectors, each slicing data from the two different state.
export const getUserFeatureState =
createFeatureSelector<IUsersFeatureState>('userFeature');
export getUserSellerDetails = (state: IUserSellerState ) =>
state.userSeller