diff --git a/package-lock.json b/package-lock.json index af6df0d..e7eb995 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2126,6 +2126,22 @@ "schema-utils": "^2.7.0" } }, + "@ngrx/effects": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-11.0.1.tgz", + "integrity": "sha512-FJa0WVr0PcPgFXCv8i//RDAVV26pl0ieOLH3yDnZN0BH6/cDeUcKtWsWv+IAiJ63dFm9VedgNgwVo0I7CP9G+g==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@ngrx/store": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-11.0.1.tgz", + "integrity": "sha512-ULk+z7fXg1S0mbSXatHplvg8Rqj9Hglo6pVugaDgLdFR3DD5Wpl0cefvLBscaeZF9DGrLBoPZVlFq/LACRr6tA==", + "requires": { + "tslib": "^2.0.0" + } + }, "@ngtools/webpack": { "version": "11.1.4", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.1.4.tgz", diff --git a/package.json b/package.json index 5ce7ca6..f4443ac 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,8 @@ "@angular/core": "~11.2.0", "@angular/platform-browser": "^11.2.3", "@angular/platform-browser-dynamic": "^11.2.3", + "@ngrx/effects": "^11.0.1", + "@ngrx/store": "^11.0.1", "rxjs": "~6.6.0", "tslib": "^2.0.0", "zone.js": "~0.11.0" diff --git a/projects/example-app/src/app/app.component.css b/projects/example-app/src/app/app.component.css index 7c0e12a..999a045 100644 --- a/projects/example-app/src/app/app.component.css +++ b/projects/example-app/src/app/app.component.css @@ -1,4 +1,8 @@ .container { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(2, 1fr); +} + +.container > * { + height: 300px; } diff --git a/projects/example-app/src/app/app.component.html b/projects/example-app/src/app/app.component.html index 2fb04bc..9dbfddb 100644 --- a/projects/example-app/src/app/app.component.html +++ b/projects/example-app/src/app/app.component.html @@ -3,4 +3,5 @@

Example App

+ diff --git a/projects/example-app/src/app/app.module.ts b/projects/example-app/src/app/app.module.ts index d5ce437..ca0c23f 100644 --- a/projects/example-app/src/app/app.module.ts +++ b/projects/example-app/src/app/app.module.ts @@ -8,6 +8,11 @@ import { LoadableComponentExampleComponent } from './components/loadable-compone import { LoadingSpinnerComponent } from './components/loading-spinner/loading-spinner.component'; import { JsonErrorComponent } from './components/json-error/json-error.component'; import { SimpleLoadableComponentExampleComponent } from './components/simple-loadable-component-example/simple-loadable-component-example.component'; +import { NgrxExampleComponent } from './components/ngrx-example/ngrx-example.component'; +import { StoreModule } from '@ngrx/store'; +import { responseReducer } from './components/ngrx-example/reducer'; +import { EffectsModule } from '@ngrx/effects'; +import { LoadEffects } from './components/ngrx-example/effects'; @NgModule({ declarations: [ @@ -17,9 +22,14 @@ import { SimpleLoadableComponentExampleComponent } from './components/simple-loa LoadableComponentExampleComponent, LoadingSpinnerComponent, JsonErrorComponent, + NgrxExampleComponent, ], imports: [ BrowserModule, + StoreModule.forRoot({ + response: responseReducer, + }), + EffectsModule.forRoot([LoadEffects]), LoadableModule.forRoot({ defaultComponents: { loading: LoadingSpinnerComponent, diff --git a/projects/example-app/src/app/components/ngrx-example/actions.ts b/projects/example-app/src/app/components/ngrx-example/actions.ts new file mode 100644 index 0000000..235bf90 --- /dev/null +++ b/projects/example-app/src/app/components/ngrx-example/actions.ts @@ -0,0 +1,16 @@ +import { createAction, props } from '@ngrx/store'; + +export const load = createAction( + '[Ngrx Example] Load', + props<{ id: number; error: boolean }>() +); + +export const loadSuccess = createAction( + '[Ngrx Example] Load success', + props<{ response: unknown }>() +); + +export const loadError = createAction( + '[Ngrx Example] Load error', + props<{ error: unknown }>() +); diff --git a/projects/example-app/src/app/components/ngrx-example/effects.ts b/projects/example-app/src/app/components/ngrx-example/effects.ts new file mode 100644 index 0000000..eb99558 --- /dev/null +++ b/projects/example-app/src/app/components/ngrx-example/effects.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { of } from 'rxjs'; +import { map, mergeMap, catchError } from 'rxjs/operators'; +import { LoadService } from '../../load.service'; +import { load, loadError, loadSuccess } from './actions'; + +@Injectable() +export class LoadEffects { + load$ = createEffect(() => + this.actions$.pipe( + ofType(load), + mergeMap((action) => + this.loadService.load(action.id, action.error).pipe( + map((response) => loadSuccess({ response })), + catchError((error) => of(loadError({ error }))) + ) + ) + ) + ); + + constructor(private actions$: Actions, private loadService: LoadService) {} +} diff --git a/projects/example-app/src/app/components/ngrx-example/ngrx-example.component.html b/projects/example-app/src/app/components/ngrx-example/ngrx-example.component.html new file mode 100644 index 0000000..04cdbf3 --- /dev/null +++ b/projects/example-app/src/app/components/ngrx-example/ngrx-example.component.html @@ -0,0 +1,7 @@ +

Ngrx example

+ + + +

Loaded

+
{{ loadable.value | json }}
+
diff --git a/projects/example-app/src/app/components/ngrx-example/ngrx-example.component.ts b/projects/example-app/src/app/components/ngrx-example/ngrx-example.component.ts new file mode 100644 index 0000000..ccd2f88 --- /dev/null +++ b/projects/example-app/src/app/components/ngrx-example/ngrx-example.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { load } from './actions'; +import { selectResponse } from './selector'; + +@Component({ + selector: 'app-ngrx-example', + templateUrl: './ngrx-example.component.html', +}) +export class NgrxExampleComponent { + loadable$ = this.store.select(selectResponse); + + constructor(private store: Store) {} + + load(id: number, error: boolean): void { + this.store.dispatch(load({ id, error })); + } +} diff --git a/projects/example-app/src/app/components/ngrx-example/reducer.ts b/projects/example-app/src/app/components/ngrx-example/reducer.ts new file mode 100644 index 0000000..4ea442c --- /dev/null +++ b/projects/example-app/src/app/components/ngrx-example/reducer.ts @@ -0,0 +1,23 @@ +import { Action, createReducer, on } from '@ngrx/store'; +import { + errored, + idle, + loaded, + loading, +} from 'projects/ngx-loadable/src/lib/loadable.constructors'; +import { Loadable } from 'projects/ngx-loadable/src/lib/loadable.type'; +import { load, loadError, loadSuccess } from './actions'; + +const reducer = createReducer( + idle as Loadable, + on(load, (_) => loading), + on(loadSuccess, (_, { response }) => loaded(response)), + on(loadError, (_, { error }) => errored(error)) +); + +export function responseReducer( + state: Loadable | undefined, + action: Action +): Loadable { + return reducer(state, action); +} diff --git a/projects/example-app/src/app/components/ngrx-example/selector.ts b/projects/example-app/src/app/components/ngrx-example/selector.ts new file mode 100644 index 0000000..66db8aa --- /dev/null +++ b/projects/example-app/src/app/components/ngrx-example/selector.ts @@ -0,0 +1,6 @@ +import { createFeatureSelector } from '@ngrx/store'; +import { Loadable } from 'projects/ngx-loadable/src/lib/loadable.type'; + +export const selectResponse = createFeatureSelector>( + 'response' +);