@ngdux/list
v3.0.1
Published
The @ngdux/list uses ngrx/store to give you a full state to make easy to load, save and delete resources. It gives also support to paging, filtering and sorting. It was created to reduce the ngrx/store boilerplate code
Downloads
12
Readme
@ngdux/list
The @ngdux/list uses ngrx/store to give you a full state to make easy to load, save and delete resources. It gives also support to paging, filtering and sorting. It was created to reduce the ngrx/store boilerplate code
Installation
npm install @ngdux/list
Example:
Option 1 - Full state
https://github.com/allanartuso/ngdux/tree/master/libs/demo/data-access/properties/src/lib/%2Bstate/properties
State
import { UserDto } from '@demo/demo/data-model/users';
import { ErrorDto } from '@ngdux/data-model-common';
import { createListState } from '@ngdux/list';
export const USERS_FEATURE_KEY = 'users';
export const {
actions: usesActions,
selectors: usersSelectors,
reducer: usersReducer,
entityAdapter: usersEntityAdapter
} = createListState<UserDto, ErrorDto>(USERS_FEATURE_KEY);
Facade
import { Injectable } from '@angular/core';
import { AbstractListFacade } from '@ngdux/list';
import { Store } from '@ngrx/store';
import { usersActions, usersSelectors } from './users.state';
import { User, Error } from './models';
@Injectable()
export class UsersFacade extends AbstractListFacade<User, Error> {
constructor(store: Store) {
super(store, usersActions, usersSelectors);
}
}
Option 2 - Separated creators for actions, reducer and selectors
Actions
import { createListActions } from '@ngdux/list';
import { User, Error } from './models';
export const usersActions = createListActions<User, Error>('Users');
Reducer
import { createListEntityAdapter, createListReducer, ListState } from '@ngdux/list';
import { Action } from '@ngrx/store';
import { User, Error } from './models';
import { usersActions } from './users.actions';
export const USERS_FEATURE_KEY = 'users';
export const entityAdapter = createListEntityAdapter<User>();
const reducer = createListReducer<User, Error>(entityAdapter, usersActions);
export function usersReducer(state: ListState<User, Error>, action: Action): ListState<User, Error> {
return reducer(state, action);
}
Selectors
import { createListSelectors, ListState } from '@ngdux/list';
import { createFeatureSelector } from '@ngrx/store';
import { User, Error } from './models';
import { entityAdapter, USERS_FEATURE_KEY } from './users.reducer';
const getState = createFeatureSelector<ListState<User, Error>>(USERS_FEATURE_KEY);
export const usersSelectors = createListSelectors(entityAdapter, getState);
Facade
import { Injectable } from '@angular/core';
import { AbstractListFacade } from '@ngdux/list';
import { Store } from '@ngrx/store';
import { usersActions } from './users.actions';
import { usersSelectors } from './users.selectors';
@Injectable()
export class UsersFacade extends AbstractListFacade<User, Error> {
constructor(store: Store) {
super(store, userActions, usersSelectors);
}
}
Option 3 - Dynamic feature key
https://github.com/allanartuso/ngdux/tree/master/libs/demo/data-access/users/src/lib/%2Bstate/users
Reducer manager service
import { Injectable } from '@angular/core';
import { User, Error } from '.../models';
import { AbstractListReducerManager } from '@ngdux/list';
@Injectable()
export class UsersReducerManager extends AbstractListReducerManager<User, Error> {}
Facade
import { Injectable } from '@angular/core';
import { AbstractListFacade } from '@ngdux/list';
import { Store } from '@ngrx/store';
import { UsersReducerManager } from './users-state.service';
@Injectable()
export class UsersFacade extends AbstractListFacade<User, Error> {
constructor(store: Store, usersReducerManager: UsersReducerManager) {
super(store, usersReducerManager.actions, usersReducerManager.selectors);
}
}
Module
import { ModuleWithProviders, NgModule } from '@angular/core';
import { LIST_FEATURE_KEY } from '@ngdux/list';
import { UsersReducerManager } from './+state/users/users-state.service';
import { UsersFacade } from './+state/users/users.facade';
@NgModule({
providers: [
UsersReducerManager,
UsersFacade
]
})
export class UsersModule {
static config(listFeatureKey: string): ModuleWithProviders<UsersModule> {
return {
ngModule: UsersModule,
providers: [
{ provide: LIST_FEATURE_KEY, useValue: listFeatureKey },
]
};
}
}
Effects
import { Injectable } from '@angular/core';
import { NotificationService } from '@demo/shared/util-notification';
import { AbstractListEffects } from '@ngdux/list';
import { Actions } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { UserService } from '../../services/user.service';
import { usersActions } from './users.actions';
import { usersSelectors } from './users.selectors';
import { User, Error } from './models';
@Injectable()
export class UsersEffects extends AbstractListEffects<User, Error> {
override texts = {
deleteConfirmationTitle: 'Delete users',
deleteConfirmationMessage: 'Are you sure to delete the selected users?',
deletedMessage: 'The users were deleted successfully.'
};
constructor(
actions$: Actions,
store: Store,
usersService: UserService,
notificationService: NotificationService
) {
super(actions$, store, usersService, usersActions, usersSelectors, notificationService);
}
}
Service
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ListService, RequestOptions } from '@ngdux/list';
import { Observable } from 'rxjs';
import { Error, User, USERS_RESOURCE_BASE_PATH } from './models';
import { createRequestParameters } from './utils';
@Injectable({
providedIn: 'root'
})
export class UserService implements ListService<User, Error> {
constructor(private httpClient: HttpClient) {}
loadResources(options: RequestOptions): Observable<User[]> {
const params = new HttpParams({ fromObject: createRequestParameters(options) });
return this.httpClient.get<User[]>(USERS_RESOURCE_BASE_PATH, { params });
}
deleteResources(ids: string[]): Observable<User[]> {
return this.httpClient.delete<User[]>(USERS_RESOURCE_BASE_PATH, { body: ids });
}
patchResources?(ids: string[], resource: Partial<User>): Observable<Array<User>> {
return this.httpClient.patch<Array<User>>(
USERS_RESOURCE_BASE_PATH,
ids.map(id => ({ id, resource }))
);
}
}
Notification Service
import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ListNotificationService } from '@ngdux/list';
import { Observable } from 'rxjs';
import { ConfirmationDialogComponent } from '../components/confirmation-dialog/confirmation-dialog.component';
import { Error } from './models';
@Injectable()
export class NotificationService implements ListNotificationService<Error> {
constructor(private readonly snackBar: MatSnackBar, private readonly dialog: MatDialog) {}
onListErrors(errors: Error): void {
this.snackBar.open(errors.message);
}
onListDelete(ids: string[]): void {
this.snackBar.open(`Resources ${ids.join(', ')} have been deleted.`);
}
openConfirmationDialog(data: { message: string; title: string }): Observable<boolean> {
const dialog = this.dialog.open(ConfirmationDialogComponent, { data });
return dialog.afterClosed();
}
}