Tobias Gassmann
Tobias Gassmann

Reputation: 11819

angular: using the same <router-outlet> twice in one component

Disclaimer: This is a duplicate of Changing router-outlet with *ngIf in app.component.html in angular2 which has an accepted answer which does not solve my situation though.

So here is my problem: I would like to have the same "router-outlet" twice in my main-component. As it seems only the second "router-outlet" wins and displays the content correctly. The propose solution of wrapping the router-outlet in a ng-template does not work for me.

This is my situation in code:

<div class="mobile-only">
  <div>some special content for mobile version</div>
  <router-outlet></router-outlet>
</div>

<div class="desktop-only">
  <div>some special content for desktop version</div>
  <router-outlet></router-outlet>
</div>

Only the second router-outlet gets updated when the user navigates the page. The first router-outlet is abandonned by angular.

Question: How can I reuse the router-outlet?

Edit: I have tried to wrap the router-outlet in a ng-template, it did not work though: https://stackblitz.com/edit/router-outlet-in-template-not-working-example-cpyjbq

And here is a working version: https://stackblitz.com/edit/router-outlet-in-template-working-example

I can actually reuse the router-outlet --- but only at the cost of reassigning the template-variable in a setTimeout. As a nasty side-effect the components are reinstantiated.

Upvotes: 3

Views: 4338

Answers (4)

Aman Goel
Aman Goel

Reputation: 55

I have tried something as follow and is helping me to show mutually exclusive

HTML

<div id="mobile">
 <router-outlet *ngIf="!getIfMobile"></router-outlet>
</div>
<div id="desktop">
 <router-outlet *ngIf="getIfMobile"></router-outlet>
</div>

Component.ts

get getIfMobile() {
    return window.innerWidth < 720;
}

Upvotes: 0

sobczi
sobczi

Reputation: 131

While trying to find work around for this I ended up with:

HTML

<div id="mobile">
 <router-outlet *ngIf="isMobile"></router-outlet>
</div>
<div id="desktop">
 <router-outlet *ngIf="isDesktop"></router-outlet>
</div>

TS

export class ExampleComponent implements AfterViewInit {

  private initied: boolean
  constructor (
    private cdref: ChangeDetectorRef
  ) { }

  ngAfterViewInit (): void {
    this.initied = true
    this.cdref.detectChanges()
  }

  get isDesktop (): boolean {
    if (!this.initied) { return false }
    return this.checkHidden('router-mobile')
  }

  get isMobile (): boolean {
    if (!this.initied) { return false }
    return this.checkHidden('router-desktop')
  }

  private checkHidden (id: string): boolean {
    return (document.getElementById(id).getAttribute('style') as string).includes('display: none')
  }
}

Upvotes: 0

Tobias Gassmann
Tobias Gassmann

Reputation: 11819

I think I have found another solution by listening to Router-Events:

https://stackblitz.com/edit/router-outlet-twice-with-events

In this stackblitz I actually have two templates using the router-outlet simultaneously. Is this a valid workaround?

Upvotes: 0

Elias Garcia
Elias Garcia

Reputation: 7282

If you want to use multiple outlets in the same component template you need to use named outlets. But they are intended to work with secondary routes and not with primary... I don't know which is your use case to have two outlets, but if you are going to display different content from mobile and desktop, you should instead consider to create two different apps, but this is only a recommendation!

So, if you want to use named outlets, you need to give each outlet a name, like this:

<div class="mobile-only">
  <div>some special content for mobile version</div>
  <router-outlet name="mobile-content"></router-outlet>
</div>

<div class="desktop-only">
  <div>some special content for desktop version</div>
  <router-outlet name="desktop-content"></router-outlet>
</div>

Then, you can redirect your routes to an specific outlet on your routing file like this:

{
  path: 'mobile',
  component: MobileContentComponent,
  outlet: 'mobile-content'
},
{
  path: 'desktop',
  component: DesktopContentComponent,
  outlet: 'desktop-content'
}

If you are redirecting to this routes through a routerLink directive, then you can redirect from the template like this:

<a [routerLink]="[{ outlets: { mobile-content: ['mobile'] } }]">Mobile Content</a>
<a [routerLink]="[{ outlets: { desktop-content: ['desktop'] } }]">Desktop Content</a>

EDIT

I just saw your code on StackBlitz and the problem is that you are displaying the router outlet template twice in the template. You need to display one or another based on a condition. I've modified your StackBlitz here with a variable that would display one or another router outlet based on a condition (you can check for the screen size or whatever you want).

But reviewing your code I don't understand why you need two router outlets... If you only want to trigger a class on the parent div of the router outlet, you can just use ngClass to use one class or another based on the scren size.

Upvotes: 2

Related Questions