4

I am trying to open an Angular route in a new tab and am having issues after adding {useHash: true} to the router. It worked fine before trying useHash, opened the tab, and brought me right to the component I wanted. Now it seems that regardless of what URL I use for opening the new tab, the router thinks I am trying to get to root ("/").

To reproduce, I have a very simple angular router:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { Page2Component } from './page2.component';
import { Page1Component } from './page1.component';

const routes: Routes = [
    { 
        path: 'page1', 
        component: Page1Component
    },
    {
        path: 'page2',
        component: Page2Component
    },
  { 
        path: '',
        component: Page1Component
    }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, {useHash: true})],
  exports: [RouterModule]
})
export class AppRoutingModule { }

This allows viewing of 2 simple components:

/page1

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-page1',
  template: `<p>page1 works!</p>
             <button (click)="openNewTab()">OPEN NEW TAB</button>`,
  styleUrls: ['./app.component.css']
})
export class Page1Component implements OnInit {

    constructor(private router:Router) { }

    ngOnInit(): void {
    }

    openNewTab():void {
        console.log('Opening new tab...');
        const url = this.router.serializeUrl(
            this.router.createUrlTree(['page2'])//, 
        );
        window.open(url);
    }
}

/page2

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-page2',
  template: `<p>page2 works!</p>`,
  styleUrls: ['./app.component.css']
})
export class Page2Component implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

Essentially, when you click the button located at some.url.com/#/page1, Angular should open a new tab showing some.url.com/#/page2. What actually happens, as I can clearly see, is it tries to open some.url.com/page2. Notice the lack of the /#. Now, if I set useHash to false, I can go from some.url.com/page1 to some.url.com/page2, no problem. I have tried manually adding the /# to the url I open in about 10 different ways, but regardless of what I try, the router sees the url for the new tab as / (root) as long as useHash is enabled.

What am I missing here?

I'll be completely honest that I don't have a great grasp on the inner workings of Angular HashLocationStrategy. Documentation and extensive research aren't helping. I know that I do need to use HashLocationStrategy due to the configuration of the server on which the actual app will eventually be hosted, so unfortunately I can't take the easy out and just set useHash to false. I also have to do this from inside the component, as I have extensive logic I need to execute before opening the new tab in my actual app, so no routerLink from in html either. I have a feeling that I am missing something simple and foundational here...

Any help would be greatly appreciated.

Working minimal Stackblitz replication: https://stackblitz.com/edit/angular-ivy-yedwyk

menzelr
  • 41
  • 1
  • 1
  • 3

2 Answers2

3

Use location.prepareExternalUrl(). Definition of prepareExternalUrl() method from Angular documentation,

Normalizes an external URL path. If the given URL doesn't begin with a leading slash ('/'), adds one before normalizing. Adds a hash if HashLocationStrategy is in use, or the APP_BASE_HREF if the PathLocationStrategy is in use.

Import Location from Angular Common:

import { Location } from '@angular/common';    

Add location service to constructor:

constructor(private router:Router,
            private location: Location) { }

Use this.location.prepareExternalUrl to create a url with # inside it so you can open it with window.open(url):

openNewTab():void {
    console.log('Opening new tab...');
    const url = this.location.prepareExternalUrl(this.router.serializeUrl(
        this.router.createUrlTree(['page2'])
    ));
    window.open(url);
}

Late but hope this help someone else.

Ken
  • 96
  • 8
0

First of all, you're trying to navigate through the app in a weird way. Just use the following approach:

this.router.navigate(['/page2']);

You must use the router instance to resolve navigation properly. Also, use the routerLink property when using tags:

<a routerLink="/page2">Navigate to /page2</a>
José Pulido
  • 432
  • 4
  • 11