Skip to content

Instantly share code, notes, and snippets.

@klinki
Created March 22, 2017 10:00
Show Gist options
  • Save klinki/7fd7cc3eadb1c120c4f007154fb7e6c0 to your computer and use it in GitHub Desktop.
Save klinki/7fd7cc3eadb1c120c4f007154fb7e6c0 to your computer and use it in GitHub Desktop.
Angular Route Flattener
import {ActivatedRouteSnapshot, UrlSegment, Params, Data, Route} from "@angular/router";
import {Type, Injectable} from "@angular/core";
import {Subject, ReplaySubject} from "rxjs";
@Injectable()
export class RouteFlattenerService {
public getFlattenedRouteData(route: ActivatedRouteSnapshot): FlattenedRouteData {
let downLevel = this.getActivatedRouteSnapshotWithChildren(route);
downLevel.splice(0, 1);
let upLevel = this.getActivatedRouteSnapshotWithParents(route);
upLevel.pop();
let result: FlattenedRouteData = this.mergeAllRoutes(
...upLevel,
this.getRoute(route),
...downLevel
);
return result;
}
public getActivatedRouteSnapshotWithParents(route: ActivatedRouteSnapshot): ActivatedRouteSnapshot[] {
let result = [ route ];
if (route.parent) {
let parents = this.getActivatedRouteSnapshotWithParents(route.parent);
result = parents.concat(result);
}
return result;
}
public getActivatedRouteSnapshotWithChildren(route: ActivatedRouteSnapshot): ActivatedRouteSnapshot[] {
let result = [ route ];
if (route.firstChild) {
let children = this.getActivatedRouteSnapshotWithChildren(route.firstChild);
result = result.concat(children);
}
return result;
}
public getFlattenedRouteBottomUp(route: ActivatedRouteSnapshot, includeSelf: boolean = true): FlattenedRouteData {
let result = { params: {}, data: {} };
if (includeSelf) {
result = this.getRoute(route);
}
if (route.parent) {
let parent = this.getFlattenedRouteBottomUp(route.parent);
result = this.mergeRoutes(parent, result);
}
return result;
}
public getFlattenedRouteTopDown(route: ActivatedRouteSnapshot, includeSelf: boolean = true): FlattenedRouteData {
let result = { params: {}, data: {} };
if (includeSelf) {
result = this.getRoute(route);
}
if (route.firstChild) {
let child = this.getFlattenedRouteTopDown(route.firstChild);
result = this.mergeRoutes(result, child);
}
return result;
}
protected getRoute(route: ActivatedRouteSnapshot): FlattenedRouteData {
let result: FlattenedRouteData = Object.assign({
snapshotsHierarchy: [ route ],
routeConfig: route.routeConfig
}, route);
return result;
}
protected getRouteConfigHierarchy(route: FlattenedRouteData): Route[] {
let routeConfig = [];
if (route.routeConfigHierarchy) {
routeConfig = [].concat(route.routeConfigHierarchy);
} else if (route.routeConfig) {
routeConfig = [].concat([ route.routeConfig ]);
}
return routeConfig;
}
protected mergeAllRoutes(...routes: FlattenedRouteData[]): FlattenedRouteData
{
let result = {
data: {},
params: {},
url: [],
routeConfigHierarchy: [],
snapshotsHierarchy: []
};
Object.assign(result.data, ...(routes.map(route => route.data)));
Object.assign(result.params, ...(routes.map(route => route.params)));
result.routeConfigHierarchy = [].concat(
...routes.map(route => this.getRouteConfigHierarchy(route))
);
result.snapshotsHierarchy = routes;
result.url = routes.map(route => route.url).filter(array => array.length > 0);
return result;
}
protected mergeRoutes(parent: FlattenedRouteData, child: FlattenedRouteData): FlattenedRouteData {
let result = {
data: {},
params: {},
url: [],
routeConfigHierarchy: [],
snapshotsHierarchy: []
};
Object.assign(result.data, parent.data, child.data);
Object.assign(result.params, parent.params, child.params);
result.routeConfigHierarchy = [].concat(
this.getRouteConfigHierarchy(parent),
this.getRouteConfigHierarchy(child)
);
result.snapshotsHierarchy = [].concat(parent.snapshotsHierarchy, child.snapshotsHierarchy);
result.url = parent.url.concat(child.url);
return result;
}
}
export interface FlattenedRouteData {
params: Params;
data: Data;
url?: UrlSegment[];
routeConfig?: Route;
routeConfigHierarchy?: Route[];
snapshotsHierarchy?: ActivatedRouteSnapshot[];
}
export interface FullFlattenedRoute {
/**
* The URL segments matched by this route.
*/
url: UrlSegment[];
/**
* The matrix parameters scoped to this route.
*/
params: Params;
/**
* The query parameters shared by all the routes.
*/
queryParams: Params;
/**
* The URL fragment shared by all the routes.
*/
fragment: string;
/**
* The static and resolved data of this route.
*/
data: Data;
/**
* The outlet name of the route.
*/
outlet: string;
/**
* The component of the route.
*/
component: Type<any> | string;
/**
* The configuration used to match this route.
*/
routeConfig: Route;
/**
* The root of the router state.
*/
root: ActivatedRouteSnapshot;
/**
* The parent of this route in the router state tree.
*/
parent: ActivatedRouteSnapshot;
/**
* The first child of this route in the router state tree.
*/
firstChild: ActivatedRouteSnapshot;
/**
* The children of this route in the router state tree.
*/
children: ActivatedRouteSnapshot[];
/**
* The path from the root of the router state tree to this route.
*/
pathFromRoot: ActivatedRouteSnapshot[];
}
import {Component, OnInit} from "@angular/core";
import {Router, ActivatedRoute} from "@angular/router";
import {RouteFlattenerService} from "../../core/routing/route-flattener.service";
@Component({
templateUrl: './some.component.html',
})
export class SomeComponent implements OnInit {
public constructor(
protected _router: Router,
protected _activatedRoute: ActivatedRoute,
protected _routeFlattener: RouteFlattenerService
) {
}
ngOnInit(): void {
this.router.events
.filter(event => event instanceof NavigationEnd)
.subscribe((event: NavigationEnd) => {
let flattenedRouteData = this._routeFlattener.getFlattenedRouteData(this._activatedRoute.snapshot);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment