Solvedangular Angular 5 - "Error: Cannot activate an already activated outlet" when named outlets are used in children

I'm submitting a...

[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

As stated here on stackoverflow when you have a routing configuration like:

export const routes = [
{
    path: '',
    component: IndexComponent, 
    children: [
        {
            path: 'home',
            children: [
                { path: '', component: FirstComponent, outlet: 'first', data: { state: 'a' } },
                { path: '', component: SecondComponent, outlet: 'second', data: { state: 'b' } }
            ]
        },
        {
            path: 'about', 
            children: [
                { path: '', component: FirstComponent, outlet: 'first', data: { state: 'b' } },
                { path: '', component: SecondComponent, outlet: 'second', data: { state: 'a' } }
            ]
        }
    ]
}

And you are navigating from /home to /about using a link <a routerLink="['/about']">about</a> it throws the following error:

ERROR Error: Uncaught (in promise): Error: Cannot activate an already activated outlet
Error: Cannot activate an already activated outlet

Expected behavior

The expected behavior would be that it navigates to /about and the router populates the named outlets with the new components (taking internally care of deactivation/activation of outlets).

Minimal reproduction of the problem with instructions

Just a simple app, with routing a named outlets with the configuration above.

What is the motivation / use case for changing the behavior?

It's a show stopper.

Environment

Angular version: 5.0.3


Browser:
- [x] Chrome (desktop) version XX
- [x] Chrome (Android) version XX
- [x] Chrome (iOS) version XX
- [x] Firefox version XX
- [x] Safari (desktop) version XX
- [x] Safari (iOS) version XX
- [x] IE version XX
- [x] Edge version XX
 
Others:
31 Answers

Ôťö´ŞĆAccepted Answer

...Ah, Do not add <route-outlet></route-outlet> to any Structural Directive(such as ngIF), angular cannot deactivate <route-outlet/> if it is not rendered ­čść

Other Answers:

We've adopted angular at my place of work, and we're relying on this technique for routing because we don't want to embed router-outlet information into the url. Until this works we'll have to rely on a fork of @angular/router that has the fix in the pull request in it to keep moving forward.

I guess it's a more involved way of +1'ing, but I just want it clear that there are others that need this fix too.

You need to change a little bit the routes. One of the 2 child routes should not be named. And of course the IndexComponent should also have two outlets one named and one without name.

export const routes = [
{
    path: '',
    component: IndexComponent, 
    children: [
        {
            path: 'home',
            children: [
                { path: '', component: FirstComponent, data: { state: 'a' } },
                { path: '', component: SecondComponent, outlet: 'second', data: { state: 'b' } }
            ]
        },
        {
            path: 'about', 
            children: [
                { path: '', component: FirstComponent, data: { state: 'b' } },
                { path: '', component: SecondComponent, outlet: 'second', data: { state: 'a' } }
            ]
        }
    ]
}

I have the same problem but I strongly disagree with replacing the error with a call to deactivate() because that is a bandaid fix that only hides the underlying problem.

A better fix would be changing the router to not call activateWith again if the outlet is already activated.

This guy's got a working answer: https://stackoverflow.com/a/55742986/3000466.
The workaround is deactivating manually the router on each event:

ngOnInit(): void {
    this.router.events.subscribe(e => {
      if (e instanceof ActivationStart && e.snapshot.outlet === "outletname")
        this.outlet.deactivate();
    });

More Issues: