angularrouteslazy-loadingangular-auxiliary-routes

Angular 6/7 Auxiliary outlet navigating to by route - clears primary outlet and it shouldn't


Lazy loading and using named outlets. I have gotten the named outlet to load as expected but when it does, it is also clearing the primary outlet. I want the primary outlet to keep the component it is displaying and just the named outlet to change to show new component.

Thanks to some help from @pixelbits... here is an example of what is not working https://stackblitz.com/edit/angular-sw6cmc

I don't want the primary outlet to change.

The html

<router-outlet></router-outlet>
<router-outlet name="dialogOutlet"></router-outlet>

The route:

 {    
    path: 'packoutdialog'
    , children:[
      {path:'', outlet:'dialogOutlet', component: PackoutComponent}]

  },

Either of these will fill the dialogOutlet but clear the primary

 this.router.navigate(['inventory', 'packoutedialog'])
this.router.navigate(['packoutdialog',{outlets:{'dialogOutlet':[]}}],{skipLocationChange: true, relativeTo: this.activatedRoute.parent});

This seems like it should work but does not.

this.router.navigate([{outlets:{'dialogOutlet':['inventory','packoutdialog']}}])

the expected result is that the primary router-outlet keeps the view in it and only the named outlet changes. Currently the named outlet is changing as expected but the primary outlet is getting cleared.


Solution

  • When you have primary outlets and auxiliary outlets together, you need to make sure that both routes fully resolve to a component. In fact, you should consider each route path in isolation.

    For example, if you have a component which sets up a router outlet, and a named router outlet:

    <router-outlet></router-outlet>
    <router-outlet name="dialogOutlet"></router-outlet>
    

    Then you need to make sure that each route can resolve to a component:

    { path: 'inventory', component: InventoryComponent, children: [...] }, 
    { path: 'packoutdialog', component: PackoutComponent, outlet: 'dialogOutlet' }
    

    Notice that the packoutdialog route for the named outlet dialogOutlet needs to be defined at the root level. If you defined the named outlet as a child route, it would never resolve.

    To navigate to these routes:

    this.router.navigate([{ outlets: { primary: 'inventory', dialogOutlet: 'packoutdialog'} }]);
    

    The primary route will resolve to the InventoryComponent and the named outlet will resolve to the PackoutComponent.

    To clear the dialog, you could specify a path for both explicitly:

    this.router.navigate([{ outlets: { primary: 'inventory', dialogOutlet: null}]);
    

    Or, if you want to be able show the dialogOutlet regardless of the primary route, you can navigate without explicitly defining a primary route:

    this.router.navigate([{ outlets: { dialogOutlet: 'packoutdialog'}]);
    

    Then to clear the dialog:

    this.router.navigate([{ outlets: { dialogOutlet: null }]);
    

    Demo

    The above also works for lazy loaded modules.

    Demo with Lazy Module 1 Demo with Lazy Module 2