问题
I have an Angular 2 app with several tabs for different features/components. One of the tabs is "Products" where I can see the list of products and search for products by typing name in a search field. So, I type a text in search text field and the matching records are filtered and displayed on the page. I can then click on the product to view its details and then come back to the main products tab. Now, I do not want to lose the search text and results on the products page. To solve this issue, I looked at the CustomReuseStrategy
My app.routing file looks somewhat like:
const appRoutes: Routes =
[
{
path: '',
component: MainComponent,
children: [
{
path: '',
canActivate: [CanActivateGuard],
children: [
{ path: 'orders', component: OrderComponent, data: { key: 1} },
{
path: 'products',
canActivate: [FeatureEnabledGuard],
component: ProductsComponent,
data: { key: 2}
children: [
{ path: '', component: FindProductComponent, data: { key: 3} },
{ path: ':id', component: ProductDetailsComponent, data: { key: 4} },
]
},
]
}
]
}
];
import {ActivatedRouteSnapshot, DetachedRouteHandle, Params,
RouteReuseStrategy} from "@angular/router";
interface RouteStorageObject {
snapshot: ActivatedRouteSnapshot;
handle: DetachedRouteHandle;
}
export class CustomReuseStrategy implements RouteReuseStrategy {
storedRoutes: { [key: string]: RouteStorageObject } = {};
getFurthestDecendantParams(route: ActivatedRouteSnapshot, sum: any):
ActivatedRouteSnapshot {
if (route.children.length > 0) {
let child: ActivatedRouteSnapshot = route.children[0];
sum.sum = sum.sum + this.sumParams
(child.params);
return this.getFurthestDecendantParams(child, sum);
}
return route;
}
sumParams(params: Params): string {
return Object.keys(params).reduce((param, key) => {
return param + params[key];
}, "");
}
calcKey(route: ActivatedRouteSnapshot) {
let paramKey = {
sum: ""
}
if (route.children.length > 0) {
this.getFurthestDecendantParams(route, paramKey).params;
} else {
paramKey.sum = this.sumParams(route.params);
}
if (paramKey.sum != "") {
paramKey.sum = "_" + paramKey.sum;
}
return route.data.key + paramKey.sum;
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
console.info("CustomReuseStrategy.shouldDetach() - route key: " +
this.calcKey(route));
return ("2" === this.calcKey(route));
}
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle):
void {
let storedRoute: RouteStorageObject = {
snapshot: route,
handle: handle
};
console.info("CustomReuseStrategy.store() - route key: " +
this.calcKey(route));
this.storedRoutes[this.calcKey(route)] = storedRoute;
}
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
console.info("CustomReuseStrategy.shouldAttach() - route key: " + this.calcKey(route));
console.log('in shouldayyach from storedoute = ' + this.storedRoutes[this.calcKey(route)]);
console.log('returned in shouldAttached = ' + (this.storedRoutes[this.calcKey(route)] !== undefined));
return this.storedRoutes[this.calcKey(route)] !== undefined;
}
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
console.info("CustomReuseStrategy.retrieve() - route key: " +
this.calcKey(route));
if (this.storedRoutes[this.calcKey(route)] === undefined) {
/* Just return undefined */
return null;
} else {
return this.storedRoutes[this.calcKey(route)].handle;
}
}
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr:
ActivatedRouteSnapshot): boolean {
let returnValue = (future.routeConfig === curr.routeConfig);
if (future.routeConfig != null && curr.routeConfig != null) {
returnValue = this.calcKey(future) === this.calcKey(curr);
console.info("CustomReuseStrategy.shouldReuseRoute() - future: " +
this.calcKey(future) + ", curr: " + this.calcKey(curr) +
", future.routeConfig.path:" + future.routeConfig.path + ", curr.routeConfig.path:" + curr.routeConfig.path + ", returnValue: " +
returnValue);
} else {
console.info("CustomReuseStrategy.shouldReuseRoute() - future: " +
this.calcKey(future) + ", curr: " + this.calcKey(curr) +
", future.routeConfig:" + future.routeConfig + ", curr.routeConfig:" + curr.routeConfig + ", returnValue: " + returnValue);
}
return returnValue;
}
}
Now, here when I click on the Products tab, do a search, and then click on a product to view its details, and then click on the other tab "Order", I get an error:
Cannot read property '_outlets' of undefined at eval
What am I am doing wrong?
回答1:
You want to persist the state of the application . This is a classic scenario for using Shared services or NGRX.
What do they do ? . All the data will be stored in a single location so that when ever any data is changed by any component it will save and inform or omit the changed data and the observers of the data will update themselves with the changed data.
来源:https://stackoverflow.com/questions/46509980/angular2-customresuestrategy-when-using-combination-of-child-and-sibling-route