Skip to content

Commit

Permalink
feat: harden API
Browse files Browse the repository at this point in the history
  • Loading branch information
LayZeeDK committed Nov 18, 2021
1 parent 8553377 commit 3bf5ed3
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 16 deletions.
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,78 @@
# @ngworker/router-component-store

Angular Router-connecting NgRx component stores.

## Compatibility

Required peer dependencies:

- Angular >=12.2
- NgRx Component Store >=12.0
- RxJS >=7.0

Published with partial Ivy compilation.

## API

Two router stores are available and implement the same public API:

| API | Description |
| ----------------------------------------------------------- | ------------------------------------------ |
| currentRoute$: Observable<MinimalActivatedRouteSnapshot> | Select the current route. |
| fragment$: Observable<string \| null> | Select the current route fragment. |
| queryParams$: Observable<Params> | Select the current route query parameters. |
| routeData$: Observable<Data> | Select the current route data. |
| routeParams$: Observable<Params> | Select the current route parameters. |
| url$: Observable<string> | Select the current URL. |
| selectQueryParam<TValue>(param: string): Observable<TValue> | Select the specified query parameter. |
| selectRouteParam<TValue>(param: string): Observable<TValue> | Select the specified route paramter. |

The `GlobalRouterStore` is never destroyed but can be injected in any class.

The `LocalRouterStore` requires a component-level provider, follows the
lifecycle of that component, and can be injected in declarables as well as
other component-level services.

### GlobalRouterStore

An application-wide router store. Can be injected in any class. Implicitly
provided in the root module injector.

Usage:

```ts
// (...)
import { GlobalRouterStore } from '@ngworker/router-component-store';

@Injectable({
providedIn: 'root',
})
export class HeroService {
activeHeroId$: Observable<number> = this.routerStore.selectQueryParam('id');

constructor(private routerStore: GlobalRouterStore) {}
}
```

### LocalRouterStore

A component-level router store. Can be injected in any directive, component,
pipe, or component-level service. Explicitly provided in a component sub-tree
using `Component.providers` or `Component.viewProviders`.

Usage:

```ts
// (...)
import { LocalRouterStore } from '@ngworker/router-component-store';

@Component({
// (...)
providers: [LocalRouterStore],
})
export class HeroDetailComponent {
heroId$: Observable<number> = this.routerStore.selectQueryParam('id');

constructor(private routerStore: LocalRouterStore) {}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
MinimalRouterStateSerializer,
MinimalRouterStateSnapshot,
} from '../@ngrx/router-store/minimal_serializer';
import { RouterComponentStore } from '../router-component-store';

interface GlobalRouterStoreState {
readonly routerState: MinimalRouterStateSnapshot;
Expand All @@ -16,7 +17,10 @@ interface GlobalRouterStoreState {
@Injectable({
providedIn: 'root',
})
export class GlobalRouterStore extends ComponentStore<GlobalRouterStoreState> {
export class GlobalRouterStore
extends ComponentStore<GlobalRouterStoreState>
implements RouterComponentStore
{
#routerState$: Observable<MinimalRouterStateSnapshot> = this.select(
(state) => state.routerState
);
Expand All @@ -25,33 +29,31 @@ export class GlobalRouterStore extends ComponentStore<GlobalRouterStoreState> {
(routerState) => routerState.root
);

currentRoute$: Observable<MinimalActivatedRouteSnapshot> = this.select(
this.#rootRoute$,
(route) => {
readonly currentRoute$: Observable<MinimalActivatedRouteSnapshot> =
this.select(this.#rootRoute$, (route) => {
while (route.firstChild) {
route = route.firstChild;
}

return route;
}
);
fragment$: Observable<string | null> = this.select(
});
readonly fragment$: Observable<string | null> = this.select(
this.#rootRoute$,
(route) => route.fragment
);
queryParams$: Observable<Params> = this.select(
readonly queryParams$: Observable<Params> = this.select(
this.#rootRoute$,
(route) => route.queryParams
);
routeData$: Observable<Data> = this.select(
readonly routeData$: Observable<Data> = this.select(
this.currentRoute$,
(route) => route.data
);
routeParams$: Observable<Params> = this.select(
readonly routeParams$: Observable<Params> = this.select(
this.currentRoute$,
(route) => route.params
);
url$: Observable<string> = this.select(
readonly url$: Observable<string> = this.select(
this.#routerState$,
(routerState) => routerState.url
);
Expand All @@ -69,11 +71,11 @@ export class GlobalRouterStore extends ComponentStore<GlobalRouterStoreState> {
}

selectQueryParam<TValue>(param: string): Observable<TValue> {
return this.queryParams$.pipe(map((params) => params[param]));
return this.select(this.queryParams$, (params) => params[param]);
}

selectRouteParam<TValue>(param: string): Observable<TValue> {
return this.routeParams$.pipe(map((params) => params[param]));
return this.select(this.routeParams$, (params) => params[param]);
}

#updateRouterState = this.updater<MinimalRouterStateSnapshot>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ import {
MinimalRouterStateSerializer,
MinimalRouterStateSnapshot,
} from '../@ngrx/router-store/minimal_serializer';
import { RouterComponentStore } from '../router-component-store';

interface LocalRouterStoreState {
readonly routerState: MinimalRouterStateSnapshot;
}

@Injectable()
export class LocalRouterStore extends ComponentStore<LocalRouterStoreState> {
export class LocalRouterStore
extends ComponentStore<LocalRouterStoreState>
implements RouterComponentStore
{
#routerState$: Observable<MinimalRouterStateSnapshot> = this.select(
(state) => state.routerState
);
Expand Down Expand Up @@ -64,11 +68,11 @@ export class LocalRouterStore extends ComponentStore<LocalRouterStoreState> {
}

selectQueryParam<TValue>(param: string): Observable<TValue> {
return this.queryParams$.pipe(map((params) => params[param]));
return this.select(this.queryParams$, (params) => params[param]);
}

selectRouteParam<TValue>(param: string): Observable<TValue> {
return this.routeParams$.pipe(map((params) => params[param]));
return this.select(this.routeParams$, (params) => params[param]);
}

#updateRouterState = this.updater<MinimalRouterStateSnapshot>(
Expand Down
15 changes: 15 additions & 0 deletions packages/router-component-store/src/lib/router-component-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Data, Params } from '@angular/router';
import { Observable } from 'rxjs';

import { MinimalActivatedRouteSnapshot } from './@ngrx/router-store/minimal_serializer';

export abstract class RouterComponentStore {
abstract readonly currentRoute$: Observable<MinimalActivatedRouteSnapshot>;
abstract readonly fragment$: Observable<string | null>;
abstract readonly queryParams$: Observable<Params>;
abstract readonly routeData$: Observable<Data>;
abstract readonly routeParams$: Observable<Params>;
abstract readonly url$: Observable<string>;
abstract selectQueryParam<TValue>(param: string): Observable<TValue>;
abstract selectRouteParam<TValue>(param: string): Observable<TValue>;
}

0 comments on commit 3bf5ed3

Please sign in to comment.