export const INCREMENT = 'INCREMENT'; export const DECREMENT = 'DECREMENT'; export const RESET = 'RESET';
import { Action } from '@ngrx/store'; const initialState = 0; export function counterReducer(state: number = initialState, action: Action) { switch (action.type) { case INCREMENT: return state + 1; case DECREMENT: return state - 1; case RESET: return 0; default: return state; } }
. import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { counterReducer } from './counter'; @NgModule({ imports: [StoreModule.forRoot({ count: counterReducer })], }) export class AppModule {}
import { Component } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { Observable } from 'rxjs'; import { INCREMENT, DECREMENT, RESET } from './counter'; interface AppState { count: number; } @Component({ selector: 'app-my-counter', template: ` <button (click)="increment()">Increment</button> <div>Current Count: {{ count$ | async }}</div> <button (click)="decrement()">Decrement</button> <button (click)="reset()">Reset Counter</button> `, }) export class MyCounterComponent { count$: Observable<number>; constructor(private store: Store<AppState>) { this.count$ = store.pipe(select('count')); } increment() { this.store.dispatch({ type: INCREMENT }); } decrement() { this.store.dispatch({ type: DECREMENT }); } reset() { this.store.dispatch({ type: RESET }); } }
import { StoreDevtoolsModule } from '@ngrx/store-devtools'; @NgModule({ imports: [ StoreModule.forRoot(reducers), // StoreModule StoreDevtoolsModule.instrument({ maxAge: 25, // 25 }), ], }) export class AppModule {}
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Action } from '@ngrx/store'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Observable, of } from 'rxjs'; import { catchError, map, mergeMap } from 'rxjs/operators'; @Injectable() export class AuthEffects { // Listen for the 'LOGIN' action @Effect() login$: Observable<Action> = this.actions$.pipe( ofType('LOGIN'), mergeMap(action => this.http.post('/auth', action.payload).pipe( // If successful, dispatch success action with result map(data => ({ type: 'LOGIN_SUCCESS', payload: data })), // If request fails, dispatch failed action catchError(() => of({ type: 'LOGIN_FAILED' })) ) ) ); constructor(private http: HttpClient, private actions$: Actions) {} }
import { EffectsModule } from '@ngrx/effects'; import { AuthEffects } from './effects/auth.effects'; @NgModule({ imports: [EffectsModule.forRoot([AuthEffects])], }) export class AppModule {}
export interface User { id: string; name: string; }
import { Action } from '@ngrx/store'; import { Update } from '@ngrx/entity'; import { User } from './user.model'; export enum UserActionTypes { LOAD_USERS = '[User] Load Users', ADD_USER = '[User] Add User', UPSERT_USER = '[User] Upsert User', ADD_USERS = '[User] Add Users', UPSERT_USERS = '[User] Upsert Users', UPDATE_USER = '[User] Update User', UPDATE_USERS = '[User] Update Users', DELETE_USER = '[User] Delete User', DELETE_USERS = '[User] Delete Users', CLEAR_USERS = '[User] Clear Users', } export class LoadUsers implements Action { readonly type = UserActionTypes.LOAD_USERS; constructor(public payload: { users: User[] }) {} } export class AddUser implements Action { readonly type = UserActionTypes.ADD_USER; constructor(public payload: { user: User }) {} } export class UpsertUser implements Action { readonly type = UserActionTypes.UPSERT_USER; constructor(public payload: { user: User }) {} } export class AddUsers implements Action { readonly type = UserActionTypes.ADD_USERS; constructor(public payload: { users: User[] }) {} } export class UpsertUsers implements Action { readonly type = UserActionTypes.UPSERT_USERS; constructor(public payload: { users: User[] }) {} } export class UpdateUser implements Action { readonly type = UserActionTypes.UPDATE_USER; constructor(public payload: { user: Update<User> }) {} } export class UpdateUsers implements Action { readonly type = UserActionTypes.UPDATE_USERS; constructor(public payload: { users: Update<User>[] }) {} } export class DeleteUser implements Action { readonly type = UserActionTypes.DELETE_USER; constructor(public payload: { id: string }) {} } export class DeleteUsers implements Action { readonly type = UserActionTypes.DELETE_USERS; constructor(public payload: { ids: string[] }) {} } export class ClearUsers implements Action { readonly type = UserActionTypes.CLEAR_USERS; } export type UserActionsUnion = | LoadUsers | AddUser | UpsertUser | AddUsers | UpsertUsers | UpdateUser | UpdateUsers | DeleteUser | DeleteUsers | ClearUsers;
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; import { User } from './user.model'; import { UserActionsUnion, UserActionTypes } from './user.actions'; export interface State extends EntityState<User> { // additional entities state properties selectedUserId: number | null; } export const adapter: EntityAdapter<User> = createEntityAdapter<User>(); export const initialState: State = adapter.getInitialState({ // additional entity state properties selectedUserId: null, }); export function reducer(state = initialState, action: UserActionsUnion): State { switch (action.type) { case UserActionTypes.ADD_USER: { return adapter.addOne(action.payload.user, state); } case UserActionTypes.UPSERT_USER: { return adapter.upsertOne(action.payload.user, state); } case UserActionTypes.ADD_USERS: { return adapter.addMany(action.payload.users, state); } case UserActionTypes.UPSERT_USERS: { return adapter.upsertMany(action.payload.users, state); } case UserActionTypes.UPDATE_USER: { return adapter.updateOne(action.payload.user, state); } case UserActionTypes.UPDATE_USERS: { return adapter.updateMany(action.payload.users, state); } case UserActionTypes.DELETE_USER: { return adapter.removeOne(action.payload.id, state); } case UserActionTypes.DELETE_USERS: { return adapter.removeMany(action.payload.ids, state); } case UserActionTypes.LOAD_USERS: { return adapter.addAll(action.payload.users, state); } case UserActionTypes.CLEAR_USERS: { return adapter.removeAll({ ...state, selectedUserId: null }); } default: { return state; } } } export const getSelectedUserId = (state: State) => state.selectedUserId; // get the selectors const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors(); // select the array of user ids export const selectUserIds = selectIds; // select the dictionary of user entities export const selectUserEntities = selectEntities; // select the array of users export const selectAllUsers = selectAll; // select the total user count export const selectUserTotal = selectTotal;
import { createSelector, createFeatureSelector, ActionReducerMap, } from '@ngrx/store'; import * as fromUser from './user.reducer'; export interface State { users: fromUser.State; } export const reducers: ActionReducerMap<State> = { users: fromUser.reducer, }; export const selectUserState = createFeatureSelector<fromUser.State>('users'); export const selectUserIds = createSelector( selectUserState, fromUser.selectUserIds ); export const selectUserEntities = createSelector( selectUserState, fromUser.selectUserEntities ); export const selectAllUsers = createSelector( selectUserState, fromUser.selectAllUsers ); export const selectUserTotal = createSelector( selectUserState, fromUser.selectUserTotal ); export const selectCurrentUserId = createSelector( selectUserState, fromUser.getSelectedUserId ); export const selectCurrentUser = createSelector( selectUserEntities, selectCurrentUserId, (userEntities, userId) => userEntities[userId] );
npm install --save @ngrx/store @ngrx/effects @ngrx/entity @ngrx/store-devtools ngrx-data
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { EntityMetadataMap, NgrxDataModule, DefaultDataServiceConfig } from 'ngrx-data'; const defaultDataServiceConfig: DefaultDataServiceConfig = { root: 'crud' }; export const entityMetadata: EntityMetadataMap = { Hero: {}, User:{} }; export const pluralNames = { Hero: 'heroes' }; @NgModule({ imports: [ CommonModule, NgrxDataModule.forRoot({ entityMetadata, pluralNames }) ], declarations: [], providers: [ { provide: DefaultDataServiceConfig, useValue: defaultDataServiceConfig } ] }) export class EntityStoreModule {}
@NgModule({ imports: [ BrowserModule, HttpClientModule, StoreModule.forRoot({}), EffectsModule.forRoot([]), EntityStoreModule, StoreDevtoolsModule.instrument({ maxAge: 25, }), ], declarations: [ AppComponent ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
const defaultDataServiceConfig: DefaultDataServiceConfig = { root: 'crud' };
export const entityMetadata: EntityMetadataMap = { Hero: {}, User:{} }; ... NgrxDataModule.forRoot({ entityMetadata, pluralNames })
export const pluralNames = { Hero: 'heroes' }; ... NgrxDataModule.forRoot({ entityMetadata, pluralNames })
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Observable } from 'rxjs'; import { Hero } from '@appModels/hero'; import { EntityServices, EntityCollectionService } from 'ngrx-data'; @Component({ selector: 'app-heroes', templateUrl: './heroes.component.html', styleUrls: ['./heroes.component.css'], changeDetection: ChangeDetectionStrategy.OnPush }) export class HeroesComponent implements OnInit { heroes$: Observable<Hero[]>; heroesService: EntityCollectionService<Hero>; constructor(entityServices: EntityServices) { this.heroesService = entityServices.getEntityCollectionService('Hero'); } ... }
ngOnInit() { this.heroes$ = this.heroesService.entities$; this.heroesService.getAll(); }
import { EntityCollectionService, EntityServices } from 'ngrx-data'; import { Hero } from '../../core'; @Component({ selector: 'app-heroes', templateUrl: './heroes.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) export class HeroesComponent implements OnInit { heroes$: Observable<Hero[]>; heroesService: EntityCollectionService<Hero>; constructor(entityServices: EntityServices) { this.heroesService = entityServices.getEntityCollectionService('Hero'); } ngOnInit() { this.heroes$ = this.heroesService.entities$; this.getHeroes(); } getHeroes() { this.heroesService.getAll(); } addHero(hero: Hero) { this.heroesService.add(hero); } deleteHero(hero: Hero) { this.heroesService.delete(hero.id); } updateHero(hero: Hero) { this.heroesService.update(hero); } }
import { Component, OnInit } from '@angular/core'; import { MessageService } from '@appServices/message.service'; import { EntityServices } from 'ngrx-data'; @Component({ selector: 'app-messages', templateUrl: './messages.component.html', styleUrls: ['./messages.component.css'] }) export class MessagesComponent implements OnInit { constructor( public messageService: MessageService, private entityServices: EntityServices ) {} ngOnInit() { this.entityServices.reducedActions$.subscribe(res => { if (res && res.type) { this.messageService.add(res.type); } }); } }
Source: https://habr.com/ru/post/418369/
All Articles