@ngrdt/router 0.0.98 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ngrdt-router.mjs +1 -1370
- package/package.json +9 -9
- package/{index.d.ts → types/ngrdt-router.d.ts} +142 -18
- package/README.md +0 -255
- package/fesm2022/ngrdt-router.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngrdt/router",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@angular/common": ">=
|
|
6
|
-
"@angular/core": ">=
|
|
7
|
-
"@angular/router": ">=
|
|
5
|
+
"@angular/common": ">=21.0.0",
|
|
6
|
+
"@angular/core": ">=21.0.0",
|
|
7
|
+
"@angular/router": ">=21.0.0",
|
|
8
8
|
"rxjs": ">=7.0.0",
|
|
9
|
-
"@ngrdt/utils": "^0.0
|
|
10
|
-
"@ngrdt/core": "^0.0
|
|
11
|
-
"@ngrdt/button": "^0.0
|
|
9
|
+
"@ngrdt/utils": "^0.1.0",
|
|
10
|
+
"@ngrdt/core": "^0.1.0",
|
|
11
|
+
"@ngrdt/button": "^0.1.0"
|
|
12
12
|
},
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"module": "fesm2022/ngrdt-router.mjs",
|
|
15
|
-
"typings": "
|
|
15
|
+
"typings": "types/ngrdt-router.d.ts",
|
|
16
16
|
"exports": {
|
|
17
17
|
"./package.json": {
|
|
18
18
|
"default": "./package.json"
|
|
19
19
|
},
|
|
20
20
|
".": {
|
|
21
|
-
"types": "./
|
|
21
|
+
"types": "./types/ngrdt-router.d.ts",
|
|
22
22
|
"default": "./fesm2022/ngrdt-router.mjs"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Provider, EnvironmentProviders, Type, Injector, InjectionToken, OnInit, OnChanges, SimpleChanges, DestroyRef } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/router';
|
|
4
|
-
import { LoadChildrenCallback, Route, ResolveFn, CanActivateFn, CanDeactivateFn, CanActivateChildFn, RunGuardsAndResolvers, Data, Params, NavigationEnd, IsActiveMatchOptions
|
|
4
|
+
import { LoadChildrenCallback, Route, ResolveFn, CanActivateFn, CanDeactivateFn, CanActivateChildFn, RunGuardsAndResolvers, Data, Params, NavigationEnd, IsActiveMatchOptions } from '@angular/router';
|
|
5
5
|
import * as _ngrdt_router from '@ngrdt/router';
|
|
6
6
|
import { Observable } from 'rxjs';
|
|
7
|
+
import { RdtGuardedContainer } from '@ngrdt/core';
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Bridges an `RdtRoute` to Angular's `Route` config.
|
|
11
|
+
* Obtained via `RdtRoute.toAngularRoute()`. Use the fluent API to attach
|
|
12
|
+
* components, guards, resolvers, and providers, then call `build()` to produce
|
|
13
|
+
* the Angular `Route` object.
|
|
14
|
+
*
|
|
15
|
+
* `build()` validates that children defined on the `RdtRoute` match the children
|
|
16
|
+
* passed via `withChildren()` — a mismatch throws at startup, catching misconfiguration early.
|
|
17
|
+
*
|
|
18
|
+
* When a route has both a component and children, `build()` automatically restructures
|
|
19
|
+
* the output into Angular's required wrapper format (parent with empty-path child for the component).
|
|
20
|
+
*/
|
|
8
21
|
declare class RdtAngularRoute<T extends object> {
|
|
9
22
|
private route;
|
|
10
23
|
private children;
|
|
@@ -103,6 +116,22 @@ declare class RdtRouteBase<T extends object> {
|
|
|
103
116
|
get children(): RdtRoute<any>[];
|
|
104
117
|
}
|
|
105
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Fluent builder for creating `RdtRoute` instances.
|
|
121
|
+
* Routes are defined once in a central file and referenced everywhere by object, eliminating string-based path typos.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* const USER_DETAIL = new RdtRouteBuilder<{ userId: number }>()
|
|
126
|
+
* .withName('User Detail')
|
|
127
|
+
* .withPath(':userId')
|
|
128
|
+
* .withParam('userId', 'number')
|
|
129
|
+
* .withCanBeEntered((route, params) => params.params.userId !== 0)
|
|
130
|
+
* .build();
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @typeParam T - Shape of the route's parameters. Enforced at compile time when navigating or creating URLs.
|
|
134
|
+
*/
|
|
106
135
|
declare class RdtRouteBuilder<T extends object = any> extends RdtRouteBase<T> {
|
|
107
136
|
get canBeEntered(): RdtCanBeEnteredFn<T>;
|
|
108
137
|
get orderedParams(): string[];
|
|
@@ -150,14 +179,14 @@ declare class RdtRouteBuilder<T extends object = any> extends RdtRouteBase<T> {
|
|
|
150
179
|
setData(data: Data): this;
|
|
151
180
|
/**
|
|
152
181
|
* Defines parameter type and lets framework parse it.
|
|
153
|
-
* @param paramName
|
|
154
|
-
* @param type
|
|
182
|
+
* @param paramName Name of the parameter in the path.
|
|
183
|
+
* @param type 'string', 'number', or an array of allowed string values (enum).
|
|
155
184
|
*/
|
|
156
|
-
withParam(paramName: keyof T, type: 'string' | 'number'): this;
|
|
185
|
+
withParam(paramName: keyof T, type: 'string' | 'number' | string[]): this;
|
|
157
186
|
/**
|
|
158
187
|
* @deprecated Use withParam() instead.
|
|
159
188
|
*/
|
|
160
|
-
setParam(paramName: keyof T, type: 'string' | 'number'): this;
|
|
189
|
+
setParam(paramName: keyof T, type: 'string' | 'number' | string[]): this;
|
|
161
190
|
/**
|
|
162
191
|
* Sets name to display in breadcrumb, etc.
|
|
163
192
|
*/
|
|
@@ -177,6 +206,19 @@ declare class RdtRouteBuilder<T extends object = any> extends RdtRouteBase<T> {
|
|
|
177
206
|
build(): RdtRoute<T>;
|
|
178
207
|
}
|
|
179
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Immutable, type-safe route definition. Created via `RdtRouteBuilder.build()`.
|
|
211
|
+
*
|
|
212
|
+
* Each instance represents a single route in the hierarchy and holds its path pattern,
|
|
213
|
+
* parameter types, parent reference, and access guard. Use `withStaticParams()`,
|
|
214
|
+
* `withQueryParams()`, or `withStateParams()` to create derived instances with
|
|
215
|
+
* pre-filled values (the original is never mutated).
|
|
216
|
+
*
|
|
217
|
+
* To bridge to Angular's router, call `toAngularRoute()` to get an `RdtAngularRoute`
|
|
218
|
+
* builder that produces an Angular `Route` config object.
|
|
219
|
+
*
|
|
220
|
+
* @typeParam T - Shape of this route's own parameters.
|
|
221
|
+
*/
|
|
180
222
|
declare class RdtRoute<T extends object = any> extends RdtRouteBase<T> {
|
|
181
223
|
private _absoluteRegex?;
|
|
182
224
|
protected _staticParams: Partial<T>;
|
|
@@ -264,23 +306,49 @@ declare class RdtRoute<T extends object = any> extends RdtRouteBase<T> {
|
|
|
264
306
|
* this route and its parents (NOT children).
|
|
265
307
|
*/
|
|
266
308
|
clone(): RdtRoute<T>;
|
|
309
|
+
private static getGroup;
|
|
267
310
|
private setRegex;
|
|
268
311
|
static fromBuilder<T extends object>(builder: RdtRouteBuilder<T>): RdtRoute<T>;
|
|
269
312
|
private static readonly groups;
|
|
270
313
|
}
|
|
271
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Defines how a route parameter is matched and parsed.
|
|
317
|
+
* - `'string'` — matches any non-slash character (`[^/]+`), value is URI-decoded.
|
|
318
|
+
* - `'number'` — matches digits only (`\d+`), value is parsed to a number.
|
|
319
|
+
* - `string[]` — enum: matches only the listed values exactly. Invalid values are rejected at both URL creation and parsing time.
|
|
320
|
+
*/
|
|
321
|
+
type ParamType = 'string' | 'number' | string[];
|
|
272
322
|
type ParamTypeMap<T> = {
|
|
273
|
-
[key in keyof T]?:
|
|
323
|
+
[key in keyof T]?: ParamType;
|
|
274
324
|
};
|
|
325
|
+
/**
|
|
326
|
+
* Maps between a database/model field name and the URL parameter name.
|
|
327
|
+
* Used with `RdtRoute.withParamMappings()` when the URL param (e.g. `:id`)
|
|
328
|
+
* differs from the property name on the data object (e.g. `userId`).
|
|
329
|
+
*/
|
|
275
330
|
interface ParamMapping {
|
|
331
|
+
/** Parameter name as it appears in the URL path (e.g. `'id'` for `:id`). */
|
|
276
332
|
urlName: string;
|
|
333
|
+
/** Property name on the data object (e.g. `'userId'`). */
|
|
277
334
|
tableName: string;
|
|
278
335
|
}
|
|
279
336
|
interface StaticRouteParams {
|
|
280
337
|
[absolutePath: string]: object;
|
|
281
338
|
}
|
|
282
339
|
type RdtRedirectReturnType = string | void | undefined;
|
|
340
|
+
/**
|
|
341
|
+
* Function invoked when a route's `canBeEntered` guard returns false.
|
|
342
|
+
* Return a URL string to redirect to, or `undefined` to block navigation without redirect.
|
|
343
|
+
* Runs in injection context — you can call `inject()` inside.
|
|
344
|
+
*/
|
|
283
345
|
type RdtRedirectFn = (currentPath: string, targetPath: string, targetRoute: RdtRoute) => RdtRedirectReturnType;
|
|
346
|
+
/**
|
|
347
|
+
* Type-safe container for route parameters keyed by route instance.
|
|
348
|
+
* Stores params for multiple routes in a hierarchy (e.g. parent + child params from a single URL).
|
|
349
|
+
* Parameters are keyed internally by absolute path, so two different `RdtRoute` instances
|
|
350
|
+
* with the same path share the same slot.
|
|
351
|
+
*/
|
|
284
352
|
declare class RdtParameters {
|
|
285
353
|
private params;
|
|
286
354
|
constructor(params?: StaticRouteParams);
|
|
@@ -291,11 +359,26 @@ declare class RdtParameters {
|
|
|
291
359
|
[Symbol.iterator](): Generator<(string | object)[], void, unknown>;
|
|
292
360
|
}
|
|
293
361
|
type LoadComponentCallback = Route['loadComponent'];
|
|
362
|
+
/**
|
|
363
|
+
* Synchronous guard function that determines whether a route can be entered.
|
|
364
|
+
* Used by `[rdtRouterLink]` and `RdtMenu` to hide/disable links, and by the
|
|
365
|
+
* built-in `canActivate` guard to block navigation.
|
|
366
|
+
* Runs in injection context when an `Injector` is available — you can call `inject()` inside.
|
|
367
|
+
*
|
|
368
|
+
* The entire parent chain is evaluated: if any ancestor's guard returns `false`, the route is blocked.
|
|
369
|
+
*/
|
|
294
370
|
type RdtCanBeEnteredFn<T extends object> = (route: RdtRoute<T>, params: RdtCombinedRouteParams<T>) => boolean;
|
|
371
|
+
/**
|
|
372
|
+
* Combined parameters available to guard functions and URL parsing results.
|
|
373
|
+
*/
|
|
295
374
|
interface RdtCombinedRouteParams<T extends object> {
|
|
375
|
+
/** Parameters extracted for the specific route being evaluated. */
|
|
296
376
|
params: Partial<T>;
|
|
377
|
+
/** Parameters for all routes in the hierarchy (parent + child), keyed by route. */
|
|
297
378
|
route: RdtParameters;
|
|
379
|
+
/** Query string parameters. */
|
|
298
380
|
query: Params;
|
|
381
|
+
/** `history.state` parameters. */
|
|
299
382
|
state: Params;
|
|
300
383
|
}
|
|
301
384
|
|
|
@@ -305,25 +388,31 @@ interface RdtCombinedRouteParams<T extends object> {
|
|
|
305
388
|
*/
|
|
306
389
|
declare const RDT_CANNOT_BE_ENTERED_PROVIDER: InjectionToken<RdtRedirectFn | RdtRedirectReturnType>;
|
|
307
390
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
declare class RdtConfirmDataLossServiceAlert extends RdtConfirmDataLossService {
|
|
313
|
-
confirmDataLoss(): Observable<boolean>;
|
|
314
|
-
}
|
|
315
|
-
|
|
391
|
+
/**
|
|
392
|
+
* Additional options for `RdtRouterService.navigate()`.
|
|
393
|
+
* These take priority over any params set on the route via `withQueryParams()` / `withStateParams()`.
|
|
394
|
+
*/
|
|
316
395
|
interface RdtNavigateExtras {
|
|
396
|
+
/** Data passed via `history.state`. */
|
|
317
397
|
state?: Params;
|
|
398
|
+
/** Query string parameters appended to the URL. */
|
|
318
399
|
query?: Params;
|
|
400
|
+
/** Window target. Use `'_blank'` to open in a new tab. Defaults to `'_self'`. */
|
|
319
401
|
target?: '_blank' | '_self' | '_parent' | '_top';
|
|
402
|
+
/** Replace the current history entry instead of pushing a new one. */
|
|
320
403
|
replaceUrl?: boolean;
|
|
321
404
|
}
|
|
405
|
+
/**
|
|
406
|
+
* Central navigation service for type-safe routing.
|
|
407
|
+
* Wraps Angular's `Router` with `RdtRoute`-based navigation, URL parsing, and history tracking.
|
|
408
|
+
* Requires `RDT_ROUTES_PROVIDER` to be configured with all application routes.
|
|
409
|
+
*/
|
|
322
410
|
declare class RdtRouterService {
|
|
323
411
|
readonly allRoutes: RdtRoute<any>[] | null;
|
|
324
412
|
readonly baseHref: string;
|
|
325
413
|
private readonly location;
|
|
326
414
|
private readonly router;
|
|
415
|
+
private readonly viewStateService;
|
|
327
416
|
private _previousUrl;
|
|
328
417
|
private _currentUrl;
|
|
329
418
|
get previousUrl(): string | null;
|
|
@@ -370,7 +459,29 @@ declare class RdtRouterService {
|
|
|
370
459
|
static ɵprov: i0.ɵɵInjectableDeclaration<RdtRouterService>;
|
|
371
460
|
}
|
|
372
461
|
|
|
462
|
+
/**
|
|
463
|
+
* Injection token holding all application routes as a flat array.
|
|
464
|
+
* Used internally by `RdtRouterService` to match URLs and enable type-safe navigation.
|
|
465
|
+
* Prefer using `provideRdtRoutes()` instead of providing this token directly.
|
|
466
|
+
*/
|
|
373
467
|
declare const RDT_ROUTES_PROVIDER: InjectionToken<RdtRoute<any>[]>;
|
|
468
|
+
/**
|
|
469
|
+
* Provides all application routes to `RdtRouterService`.
|
|
470
|
+
* Accepts either a route module object (`import * as routes from './routes'`)
|
|
471
|
+
* or a plain array of `RdtRoute` instances.
|
|
472
|
+
*
|
|
473
|
+
* @example
|
|
474
|
+
* ```ts
|
|
475
|
+
* import * as ALL_ROUTES from './rdt-routes';
|
|
476
|
+
*
|
|
477
|
+
* export const appConfig: ApplicationConfig = {
|
|
478
|
+
* providers: [
|
|
479
|
+
* provideRdtRoutes(ALL_ROUTES),
|
|
480
|
+
* ],
|
|
481
|
+
* };
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
declare function provideRdtRoutes(routes: Record<string, unknown> | RdtRoute[]): EnvironmentProviders;
|
|
374
485
|
|
|
375
486
|
declare enum RdtNavigationSource {
|
|
376
487
|
BREADCRUMB = "breadcrumb"
|
|
@@ -447,16 +558,29 @@ declare class RdtRouterLinkDirective<T extends object> {
|
|
|
447
558
|
static ɵdir: i0.ɵɵDirectiveDeclaration<RdtRouterLinkDirective<any>, "[rdtRouterLink]", never, { "routeInput": { "alias": "rdtRouterLink"; "required": true; "isSignal": true; }; "target": { "alias": "target"; "required": false; "isSignal": true; }; "params": { "alias": "params"; "required": false; "isSignal": true; }; "queryParams": { "alias": "queryParams"; "required": false; "isSignal": true; }; "stateParams": { "alias": "stateParams"; "required": false; "isSignal": true; }; "disabled": { "alias": "rdtDisabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof i1.RouterLink; inputs: { "target": "target"; "replaceUrl": "replaceUrl"; }; outputs: {}; }]>;
|
|
448
559
|
}
|
|
449
560
|
|
|
561
|
+
/**
|
|
562
|
+
* Ensures that `preventDataLossGuardFn` is applied to every route at runtime,
|
|
563
|
+
* even if it was not explicitly added in the route definition.
|
|
564
|
+
* Call `ensureGlobalGuards()` once during app initialization.
|
|
565
|
+
*
|
|
566
|
+
* Also patches the browser back button behavior: replaces the URL back to the
|
|
567
|
+
* previous value during guard checks so the address bar doesn't flash the new URL
|
|
568
|
+
* before the guard potentially rejects it.
|
|
569
|
+
*/
|
|
450
570
|
declare class GlobalRouteGuardService {
|
|
451
|
-
private router;
|
|
452
|
-
constructor(router: Router);
|
|
571
|
+
private readonly router;
|
|
453
572
|
ensureGlobalGuards(): void;
|
|
454
573
|
private ensureCanDeactivateGuards;
|
|
455
574
|
static ɵfac: i0.ɵɵFactoryDeclaration<GlobalRouteGuardService, never>;
|
|
456
575
|
static ɵprov: i0.ɵɵInjectableDeclaration<GlobalRouteGuardService>;
|
|
457
576
|
}
|
|
458
577
|
|
|
459
|
-
|
|
578
|
+
/**
|
|
579
|
+
* `CanDeactivate` guard that blocks navigation when there are unsaved changes.
|
|
580
|
+
* The routed component must implement `RdtGuardedContainer` from `@ngrdt/core`.
|
|
581
|
+
* Add to routes via `RdtAngularRoute.addCanDeactivate(preventDataLossGuardFn)`.
|
|
582
|
+
*/
|
|
583
|
+
declare const preventDataLossGuardFn: CanDeactivateFn<RdtGuardedContainer>;
|
|
460
584
|
|
|
461
|
-
export { GlobalRouteGuardService, PERMISSION_DISABLED_KEY, RDT_CANNOT_BE_ENTERED_PROVIDER,
|
|
585
|
+
export { GlobalRouteGuardService, PERMISSION_DISABLED_KEY, RDT_CANNOT_BE_ENTERED_PROVIDER, RDT_ROUTES_PROVIDER, RdtAngularRoute, RdtAnyRouteActiveDirective, RdtBackLinkDirective, RdtNavigationSource, RdtParameters, RdtRoute, RdtRouteBuilder, RdtRouterLinkDirective, RdtRouterService, preventDataLossGuardFn, provideRdtRoutes };
|
|
462
586
|
export type { RdtCanBeEnteredFn, RdtNavigateExtras };
|
package/README.md
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
# @ngrdt/router
|
|
2
|
-
|
|
3
|
-
Main use for this package is to define routes and their parameters in one place in app. It is recommended to define special `routes` module in every app using `@ngrdt/router` where all `RdtRoute` objects are defined using `RdtRouteBuilder`. Individual application modules then import these objects, define Angular routes and provide implementation details such as which component is rendered, state, guards, etc.
|
|
4
|
-
|
|
5
|
-
This approach ensures that each route is defined exactly once and can be easily edited if necessary. `@ngrdt/router` also provides set of useful tools to help you with common routing tasks.
|
|
6
|
-
|
|
7
|
-
### Instalation
|
|
8
|
-
|
|
9
|
-
`npm install @ngrdt/router`
|
|
10
|
-
|
|
11
|
-
## Basic usage
|
|
12
|
-
|
|
13
|
-
### Application routes file
|
|
14
|
-
|
|
15
|
-
Create special `nx` library (not `NgModule`) for instance `@example-app/routes`. In this library you will create file called `routes.ts` and in it individual `RdtRoute` objects like so:
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
export const DASHBOARD_ITEM_ROUTE = new RdtRouteBuilder()
|
|
19
|
-
.setName('Dashboard item')
|
|
20
|
-
.setPath(':id')
|
|
21
|
-
.setParam('id', 'number')
|
|
22
|
-
.build();
|
|
23
|
-
|
|
24
|
-
export const DASHBOARD_ROUTE = new RdtRouteBuilder()
|
|
25
|
-
.setName('Dashboard')
|
|
26
|
-
.setPath('dashboard')
|
|
27
|
-
.setChildren(DASHBOARD_ITEM_ROUTE)
|
|
28
|
-
.build();
|
|
29
|
-
|
|
30
|
-
export const SETTINGS_ROUTE = new RdtRouteBuilder()
|
|
31
|
-
.setName('Settings')
|
|
32
|
-
.setPath('settings')
|
|
33
|
-
.setCanBeEntered(() =>
|
|
34
|
-
inject(ExampleAppPermissionService).hasPermission('SETTINGS_ACCESS')
|
|
35
|
-
)
|
|
36
|
-
.build();
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
This file should only contain imports to interfaces used by `RdtRouteBuilder` as template parameter. No component, ngModule or guards such as `CanActivateFn` should be imported here. This approach will save you later headache with circular dependency.
|
|
40
|
-
|
|
41
|
-
`RdtRouterService` needs to be aware of all routes defined therefore you must provide it in your `ApplicationConfig` like so:
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
import { RDT_ROUTES_PROVIDER, RdtRoute } from '@ngrdt/router';
|
|
45
|
-
import * as ALL_ROUTES_OBJ from './rdt-routes';
|
|
46
|
-
const ALL_ROUTES = Object.values(ALL_ROUTES_OBJ) as RdtRoute[];
|
|
47
|
-
|
|
48
|
-
export const appConfig: ApplicationConfig = {
|
|
49
|
-
providers: [
|
|
50
|
-
{
|
|
51
|
-
provide: RDT_ROUTES_PROVIDER,
|
|
52
|
-
useValue: ALL_ROUTES,
|
|
53
|
-
},
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Angular routes files
|
|
59
|
-
|
|
60
|
-
Now you have to bind `RdtRoute` objects to individual modules, components, states, effects, guards and other implementation details. Instead of defining routes directly you import `RdtRoute` from `@example-app/routes` and then define `routes.ts` like so:
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
export const routes: Route[] = [
|
|
64
|
-
DASHBOARD_ROUTE.toAngularRoute()
|
|
65
|
-
.setComponent(DashboardComponent)
|
|
66
|
-
.setChildren(
|
|
67
|
-
DASHBOARD_ITEM_ROUTE.toAngularRoute()
|
|
68
|
-
.setComponent(DashboardItemComponent)
|
|
69
|
-
.addCanDeactivate(preventDataLossGuardFn)
|
|
70
|
-
.build()
|
|
71
|
-
)
|
|
72
|
-
.build(),
|
|
73
|
-
]
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
This array is then used as in regular Angular project. Note that child routes must be added as children here as well.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
### Child routes and parameters
|
|
80
|
-
|
|
81
|
-
You may nest child routes and also create routes with typed parameters to link them with particular type.
|
|
82
|
-
|
|
83
|
-
For instance lets say there's a route displaying users which has a child route to display more information about a single user. By providing `User` type to `RdtRouteBuilder` and defining types of parameters we can use `RdtRoute` object to parse path to extract parameters.
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
interface User {
|
|
87
|
-
userId: number;
|
|
88
|
-
name: string;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export const USER_DETAIL_ROUTE = new RdtRouteBuilder<User>()
|
|
92
|
-
.setName('User detail')
|
|
93
|
-
.setPath(':userId/:name')
|
|
94
|
-
.setParam('userId', 'number')
|
|
95
|
-
.setParam('name', 'string')
|
|
96
|
-
.build();
|
|
97
|
-
|
|
98
|
-
export const USER_LIST_ROUTE = new RdtRouteBuilder()
|
|
99
|
-
.setName('Users')
|
|
100
|
-
.setPath('users')
|
|
101
|
-
.setChildren(USER_DETAIL_ROUTE)
|
|
102
|
-
.build();
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Then we navigate to user detail like so:
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
const params: Partial<User> = {
|
|
109
|
-
userId: 123,
|
|
110
|
-
name: 'Josef',
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
inject(RdtRouterService).navigate(USER_DETAIL_ROUTE, params);
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
`RdtRouterService` is aware of the type so you can use it to parse absolute path into `User` object. Route knows `userId` is `number` so it will parse it. If parameter is missing or is of wrong type, then `parseAbsoluteUrl` returns `null`. Return value is a wrapper object with `get(route: RdtRoute)` method to get parsed parameters of given route or its parents.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
const user: User = USER_DETAIL_ROUTE
|
|
121
|
-
.parse('/users/123/Josef')
|
|
122
|
-
.get(USER_DETAIL_ROUTE);
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### More parameter examples
|
|
126
|
-
|
|
127
|
-
#### Static parameters
|
|
128
|
-
|
|
129
|
-
Imagine your app contains list of users and each user has set of tasks. The routes are defined as follows:
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
interface User {
|
|
133
|
-
userId: number,
|
|
134
|
-
name: string,
|
|
135
|
-
address: string,
|
|
136
|
-
tasks: Task[]
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
interface Task {
|
|
140
|
-
taskId: number,
|
|
141
|
-
description: string
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
export const TASK_DETAIL_ROUTE = new RdtRouteBuilder<Task>()
|
|
146
|
-
.setName('Task detail')
|
|
147
|
-
.setPath('task/:taskId')
|
|
148
|
-
.setParam('taskId', 'number')
|
|
149
|
-
.build();
|
|
150
|
-
|
|
151
|
-
export const USER_DETAIL_ROUTE = new RdtRouteBuilder<User>()
|
|
152
|
-
.setName('User detail')
|
|
153
|
-
.setPath(':userId')
|
|
154
|
-
.setParam('userId', 'number')
|
|
155
|
-
.setChildren(TASK_DETAIL_ROUTE)
|
|
156
|
-
.build();
|
|
157
|
-
|
|
158
|
-
export const USER_LIST_ROUTE = new RdtRouteBuilder()
|
|
159
|
-
.setName('Users')
|
|
160
|
-
.setPath('user')
|
|
161
|
-
.setChildren(USER_DETAIL_ROUTE)
|
|
162
|
-
.build();
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
This translates into path `/user/:userId/task/:taskId` for task detail route.
|
|
166
|
-
|
|
167
|
-
Now inside `UserDetailComponent` there's a for loop rendering individual tasks and you want to have links to them. You cannot use directly:
|
|
168
|
-
|
|
169
|
-
```html
|
|
170
|
-
<button [rdtRouterLink]="TASK_DETAIL_ROUTE" [params]="task"></button>
|
|
171
|
-
```
|
|
172
|
-
Because task does not specify `userId`. For this you must provide static parameters for every parent route - `User` for `USER_DETAIL_ROUTE` in this case:
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
@Input()
|
|
176
|
-
user!: User;
|
|
177
|
-
|
|
178
|
-
taskRoute!: RdtRoute<Task>;
|
|
179
|
-
|
|
180
|
-
ngOnInit() {
|
|
181
|
-
this.taskRoute = TASK_DETAIL_ROUTE.withStaticParams(USER_DETAIL_ROUTE, this.user);
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
Method `withStaticParams()` returns clone of `TASK_DETAIL_ROUTE` and all of its parent routes while fixing parameters. You can chain calling `withStaticParams` with itself or other method calls.
|
|
185
|
-
|
|
186
|
-
```html
|
|
187
|
-
<button [rdtRouterLink]="taskRoute" [params]="task"></button>
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## Ecosystem
|
|
191
|
-
|
|
192
|
-
### RdtRouterLink
|
|
193
|
-
|
|
194
|
-
`RdtRouterLink` is equivalent of `RouterLink` in Angular. It supports basically the same functionality, but adds type safety. `RdtRouterLink` will be disabled if `canBeEntered` of its route returns `false`.
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
readonly userRoute = USER_DETAIL_ROUTE;
|
|
198
|
-
readonly user$ = inject(UserService).getUser$();
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
```html
|
|
202
|
-
<button
|
|
203
|
-
[rdtRouterLink]="userRoute"
|
|
204
|
-
[params]="user$ | async"
|
|
205
|
-
target="_blank">
|
|
206
|
-
Link to user
|
|
207
|
-
</button>
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### RdtMenu
|
|
211
|
-
|
|
212
|
-
`RdtRoute` can be passed directly into `RdtMenuItem`. If `canBeEntered` returns `false`, then the item won't be visible. This is useful to hide items user has no permission for.
|
|
213
|
-
|
|
214
|
-
Method `withStaticParams` lets us provide parameters for given `RdtRoute`, because `RdtMenuItem` does not accept route parameters.
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
public getMenuItems(): RdtMenuItem[] {
|
|
218
|
-
const user: Partial<User> = {
|
|
219
|
-
userId: 123,
|
|
220
|
-
name: 'Josef'
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
return [
|
|
224
|
-
{
|
|
225
|
-
label: 'All users',
|
|
226
|
-
routerLink: USER_LIST_ROUTE
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
label: 'Josef',
|
|
230
|
-
routerLink: USER_DETAIL_ROUTE.withStaticParams(user)
|
|
231
|
-
}
|
|
232
|
-
];
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### RdtAngularRoute
|
|
237
|
-
|
|
238
|
-
`RdtAngularRoute` is a container class for `RdtRoute` which functionally does two things: verifies that routes were defined correctly and enables you to provide guards, effects, component or module. Don't forget to call `build()` for it to generate Angular `Route`.
|
|
239
|
-
|
|
240
|
-
### RdtRouterService
|
|
241
|
-
|
|
242
|
-
`RdtRouterService` has similar features as Angular `Router`.
|
|
243
|
-
|
|
244
|
-
#### `parseAbsoluteUrl()`
|
|
245
|
-
Method will parse absolute path, recognize `RdtRoute` and parse its parameters. If no parameter is provided, then window location is used.
|
|
246
|
-
|
|
247
|
-
#### `navigateBack()`
|
|
248
|
-
|
|
249
|
-
Will push parent route to navigation stack. Function works anywhere in the app unlike similar Angular-based solution using `ActivatedRoute`.
|
|
250
|
-
|
|
251
|
-
Hitting native browser back button will take you back forward. In case you want true back function, use `inject(Location).back()` which removes from navigation stack, but can potentially take you outside of the app or close browser window.
|
|
252
|
-
|
|
253
|
-
#### `previousUrl` and `currentUrl`
|
|
254
|
-
|
|
255
|
-
Cached sync values of previous and current path values. For example `/dashboard` or `/user/123/task/xyz`.
|