Using the Angular router how do I share routes across multiple named outlets

↘锁芯ラ 提交于 2020-04-16 03:51:53

问题


I have an application where I want to show the same set of components / routes in multiple places in the application. Think something like multiple panels or side bars where the user can show the same components in multiple locations depending upon what they select.

For example the user may want to "show the status component in side panel" or "show the status component in bottom right panel on page".

(In my case the number of outlets is fixed, but the same concept could be used for a dashboard style UI with a dynamic number of cards that each have a route for the component to load)

My idea was to use the angular router with named outlets for this. That would allow for easy reuse of components supporting dynamic creation as well as keeping the current routing state in the URL for easy reloading.

So for example a url may look like:

https://.../app(side:status_comp//popup:other_comp)

I have named outlets working, but what I can't figure out how to do is to reuse a route across multiple named outlets without duplicating the route in the router config.

For example:

const appRoutes: Routes = [
  { path: 'main', component: AppComponent },  

  // ==> Have to repeat each route for each outlet name
  { path: 'comp_a', component: CompA, outlet: 'first' },  
  { path: 'comp_b', component: CompB, outlet: 'first' },  
  { path: 'comp_a', component: CompA, outlet: 'second' },  
  { path: 'comp_b', component: CompB, outlet: 'second' },   

  // ==> Would like to just do this
  /*
  { path: 'comp_a', component: CompA},  
  { path: 'comp_b', component: CompB},  
  */

  { path: '', redirectTo: '/main', pathMatch: 'full' },
  { path: '**', redirectTo: '/main' }
];

Simplified Template:

<p>Outlet 1</p>
<a [routerLink]="[{ outlets: { first: ['comp_a'] } }]">Comp A</a>
<a [routerLink]="[{ outlets: { first: ['comp_b'] } }]">Comp B</a>

<div class="outlet-wrapper">    
  <router-outlet name="first"></router-outlet> 
</div>

<p>Outlet 2</p>
<a [routerLink]="[{ outlets: { second: ['comp_a'] } }]">Comp A</a>
<a [routerLink]="[{ outlets: { second: ['comp_b'] } }]">Comp B</a>

<div class="outlet-wrapper">  
   <router-outlet name="second"></router-outlet>
</div>

Then route the component into the outlet using:

this.router.navigate([{outlets: {first: ['comp_a']}}]);

What I would like is to just set the router with a single route to the given component and then be able to call router.navigate with any defined route but tell it to load that route in the named outlet.

Is there any way to do this.

Here is a sample on stackblitz where I have everything setup. ng-router-reuse app

The change I want to make is shown above and in the same in the route definitions.

Any ideas?

Note: I know I could use something like Portals from the Angular CDK and dynamically load the components. The problem with that though is that the state of what the user is seeing doesn't get stored into the URL to manage by the router and it also prevents the use of router lazy loading.


回答1:


It looks like you can update router configs dynamically at runtime, at the time of navigation. Here is an example. https://stackblitz.com/edit/ng-router-reuse-c7j96a

And here is a brief explanation.

1) On link or button click find the route in the router config.

 let route = this.router.config.filter(r => r.path === 'comp_a' && r.outlet === 'second')[0];

2) if the route does not exist add it to the configuration.

if(!route){
  this.router.config.unshift({path:'comp_a',outlet:'second',component:CompA})
}

we are using unshift method and not the push here because we don't want to add new route at the end. We always want to keep ** as the last route.

3) Then simply navigate to the route.

this.router.navigate([{outlets: {second: ['comp_a']}}]);

This solution can be helpful when the application is already loaded. But if you try to load a URL which has a path with a named outlet and if that route is not defined in the router configuration it will throw an error.

To overcome that situation you can listen to the NavigationStart event at the module level and there you can examine the URL and add routes accordingly. Though it is possible to do it does not feels clean to me. I hope this will help.



来源:https://stackoverflow.com/questions/55261876/using-the-angular-router-how-do-i-share-routes-across-multiple-named-outlets

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!