-
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(router): add service for observing route data (#2778)
- Loading branch information
Showing
5 changed files
with
147 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { ActivatedRouteSnapshot } from '@angular/router'; | ||
|
||
import { daffRouterDataCollect } from './collect-data'; | ||
|
||
describe('@daffodil/router | daffRouterDataCollect', () => { | ||
let route: ActivatedRouteSnapshot; | ||
let result: any; | ||
|
||
beforeEach(() => { | ||
route = <ActivatedRouteSnapshot><unknown>{ | ||
data: { | ||
root: 'TestClass', | ||
overwrite: 'TestClass', | ||
}, | ||
children: [ | ||
<ActivatedRouteSnapshot><unknown>{ | ||
data: { | ||
'00': 'TestClass', | ||
}, | ||
children: [ | ||
<ActivatedRouteSnapshot><unknown>{ | ||
data: { | ||
10: 'TestClass', | ||
}, | ||
children: [], | ||
}, | ||
<ActivatedRouteSnapshot><unknown>{ | ||
data: { | ||
11: 'TestClass', | ||
overwrite: 'TestClass1', | ||
}, | ||
children: [ | ||
<ActivatedRouteSnapshot><unknown>{ | ||
data: { | ||
20: 'TestClass', | ||
}, | ||
children: [], | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
<ActivatedRouteSnapshot><unknown>{ | ||
data: { | ||
'01': 'TestClass', | ||
}, | ||
children: [], | ||
}, | ||
], | ||
}; | ||
|
||
result = daffRouterDataCollect(route); | ||
}); | ||
|
||
it('should collect all the named views and combine them into a single dict', () => { | ||
expect(result['root']).toBeDefined(); | ||
expect(result['00']).toBeDefined(); | ||
expect(result['01']).toBeDefined(); | ||
expect(result[10]).toBeDefined(); | ||
expect(result[11]).toBeDefined(); | ||
expect(result[20]).toBeDefined(); | ||
expect(result['overwrite']).toBeDefined(); | ||
}); | ||
|
||
it('should give precedence to more deeply nested routes when there is a collision', () => { | ||
expect(result['overwrite']).toEqual('TestClass1'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { | ||
ActivatedRouteSnapshot, | ||
Route, | ||
} from '@angular/router'; | ||
|
||
import { collect } from '@daffodil/core'; | ||
|
||
/** | ||
* Collects data defined in the entire tree of routes. | ||
* Shallow merges data, preferring fields of more deeply nested routes. | ||
*/ | ||
export const daffRouterDataCollect = (route: ActivatedRouteSnapshot): Route['data'] => { | ||
const ary = collect(route, (r) => r.children); | ||
const ret = ary.reduce( | ||
(acc, r) => r.data | ||
? { | ||
...acc, | ||
...r.data, | ||
} | ||
: acc, | ||
{}, | ||
); | ||
return ret; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { daffRouterNamedViewsCollect } from './collect-data'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './helpers/public_api'; | ||
export * from './service/data.service'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { | ||
ActivatedRoute, | ||
NavigationEnd, | ||
Route, | ||
Router, | ||
} from '@angular/router'; | ||
import { | ||
Observable, | ||
filter, | ||
map, | ||
merge, | ||
} from 'rxjs'; | ||
|
||
import { daffRouterDataCollect } from '../helpers/collect-data'; | ||
|
||
@Injectable({ | ||
providedIn: 'root', | ||
}) | ||
export class DaffRouterDataService { | ||
/** | ||
* A collection of all the route data defined in any part of the currently activated route's tree. | ||
* Child route's data takes precendence over parent data. | ||
*/ | ||
public data$: Observable<Route['data']>; | ||
|
||
constructor( | ||
private route: ActivatedRoute, | ||
private router: Router, | ||
) { | ||
/** | ||
* Because data won't reemit for route changes and | ||
* the top-level data probably won't have named views | ||
* anyway, use `url` and router events to listen for route changes | ||
* and pull named views from nested data in the snapshot. | ||
* | ||
* On first page load, this directive will likely not be instantiated | ||
* in time to catch router events so route.url emits for this case. | ||
* On subsequent route changes, `route.url` will not change (why????) | ||
* so we use router events instead. | ||
*/ | ||
this.data$ = merge( | ||
this.router.events.pipe( | ||
filter((e) => e instanceof NavigationEnd), | ||
), | ||
this.route.url, | ||
).pipe( | ||
map(() => this.route.snapshot), | ||
map(daffRouterDataCollect), | ||
); | ||
} | ||
} |