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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With