简体   繁体   中英

Angular 9 - Cannot deactivate router outlet on lazy loaded module

Baiscally I have a component which needs to be displayed conditionally upon the activation/deactivation of a named router-outlet . All right on the activation side, but it doesn't work when the url changes back (ie someone presses the browser's back arrow): the router-outlet content still being displayed. I think the main problem is that router-outlet being part of a lazy loaded module . I've checked this previous answer for Angular 7, but it has no effects on my project (Angular 9).

Here's my routing module routes

const routes: Routes = [
  { path: '',  component: StudentsComponent },
  { path: ':id/macro',
      component: StudentDetailComponent,
      runGuardsAndResolvers: 'always',
      resolve: { 
        item: StudentDetailResolverService,
        macroAssignments: MacroAssignmentsResolverService
      },
      children: [
        {
          path: ':id/lto',      // ***** PROBLEMS HERE ************************************
          loadChildren: () => import('../lto/lto.module').then(m => m.LTOModule),
          runGuardsAndResolvers: 'always',
        }
      ]
  }
];

And that's the template where's the router-outlet directive

<app-item-detail>
    ...
    <div *ngIf="!outlet.isActivated" list >
        <app-student-detail-macro-list [student]="this.item" [macroAssignments]="this.macroAssignments" ></app-student-detail-macro-list>
    </div>

</app-item-detail>

<router-outlet #outlet="outlet" name='lto-list' (deactivate)='checkOutlet($event)' (activate)='checkOutlet($event)' ></router-outlet>

NOTE: checkOutlet($event) is simply a test to print something on the console when the router-outlet builtin event emitter fires something. This lead me to discover an event is correctly fired when the router-outlet activates, but nothing happens when the the url changes back (so, the router-outlet should deactivates).

Finally, the routing module of the lazy loaded module LTOModule

const routes: Routes = [
  { path: '' , component: LtoListComponent, outlet: 'lto-list' },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class LTORoutingModule { }

Don't know if it could be useful, but here's also the portion of template where my router-outlet is being activated

<li *ngFor="let macroAssignment of this.macroAssignments" >
    <a [routerLink]="[macroAssignment.macro, 'lto']" >
        <span >{{ macroAssignment.macro_name }}</span>
    </a>
</li>

**************** EDIT *****************

I've noticed that when I press the forth arrow instead, I get the following error: ERROR Error: Uncaught (in promise): Error: Cannot activate an already activated outlet

I guess that is nothing to do with lazy loaded. You just have to reset the conditions by implementing ngOnDestroy() of the component which gets rendered on clicking the back button.

I've found this (ugly, IMHO) workaround. In the component which contains the router-outlet directive, I subscribe to the router event to track changes in the url when the router-outlet is first activated. Then, when the url changes back to the one matching the parent component path, I deactivate the router-outlet.

onActiveOutlet(component: Component) {
    let previousUrl = this.router.url;
        this.router.events.subscribe(
          event => {
            if (event instanceof NavigationEnd) {
              if (previousUrl != this.router.url && previousUrl.includes(this.router.url)) {
                this.outlet.deactivate();
              }
            }
        }
    )
}

And in the parent component template, just catch the event emitted by the outlet when it's activating

<router-outlet #outlet="outlet" name='lto-list' (activate)='onActiveOutlet($event)' ></router-outlet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM