3

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.

Tobias Gassmann
  • 11,399
  • 15
  • 58
  • 92

4 Answers4

2

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.

Elias Garcia
  • 6,772
  • 11
  • 34
  • 62
  • Thanks for your answer! Unfortunately I cannot use different routes for different screen-sizes... – Tobias Gassmann Mar 21 '19 at 16:31
  • Is there a way to simply repeat the same content of the router-outlet? I tried putting it in a ng-template, but that did not work either... – Tobias Gassmann Mar 21 '19 at 16:33
  • Why not? If you trigger the route redirection from the .ts files you can check the screen size and load one route or another based on the screen size. Anyway, the recommended approach would be to have two different apps... – Elias Garcia Mar 21 '19 at 16:34
  • Also yes, I've tried the ng-template trick in an older project and it was working fine... Can you share some code of what have you tried in a Stackblitz to help you? – Elias Garcia Mar 21 '19 at 16:40
  • (I needed the router-outlet twice because the html-template is quite involved and more complex than in my example on stackblitz) Thanks again! :-) – Tobias Gassmann Mar 22 '19 at 11:07
  • I've got the same problem and using different routes is not a possibility. I tried using a npm package that let me detect screen sizes, but still only the second outlet works correctly even though in the resulting html there's only one outlet. – eddy Jun 03 '20 at 14:31
0

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?

Tobias Gassmann
  • 11,399
  • 15
  • 58
  • 92
0

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')
  }
}
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
sobczi
  • 121
  • 7
0

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;
}
Aman Goel
  • 55
  • 3
  • While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Tomer Shetah Dec 15 '20 at 13:37