17

I'm replacing an existing AngularJS 1.6.x SPA with an Angular 5.x SPA and I want to make the change transparent to my users.

I'm concerned about users who have bookmarks to the existing app because it has hashes in the URLs (for example: example.com/#/menu and example.com/#/item/37);

However, the new app does not have hashes in the URLs (for example: example.com/menu and example.com/item/37).

The paths and routing are all the same, with the exception of the #/ in the current app.

Is there a way I can configure the Angular routing to drop the #/ and use the hash-free routing configuration of the new app?

I could duplicate all of my routing to accommodate paths with and without the hash, but there must be a way that doesn't require doubling my code.

// Don't really want to do this:
const routes: Routes = [
  {
    path: 'menu',
    component: MenuComponent
  },
  {
    path: '#/menu',
    component: MenuComponent
  },
  // etc.
];

Similarly, redirecting every #/ path would double the code, too.

// Don't really want to do this:
const routes: Routes = [
  {
    path: 'menu',
    component: MenuComponent
  },
  {
    path: '#/menu',
    redirectTo: 'menu'
  },
  // etc.
];

I'm hoping there is something along these lines:

{
  path: '#/*',
  redirectTo: '*' // Somehow reference the wildcard part of the path here 
}

Thanks in advance for your assistance.

Kabb5
  • 3,760
  • 2
  • 33
  • 55
  • see this https://angular.io/guide/router#appendix-locationstrategy-and-browser-url-styles – Vikas Mar 27 '18 at 18:19

2 Answers2

20

The answer posted by @Yanis almost worked, but required a few slight tweaks. His answer definitely deserves an upvote; however, below is the working solution I implemented:

export class AppComponent implements OnInit {
    constructor (private router: Router) { }

    ngOnInit() {
      this.router.events.subscribe(event => {
        if (event instanceof NavigationStart) {
          if (!!event.url && event.url.match(/^\/#/)) {
            this.router.navigate([event.url.replace('/#', '')]);
          }
        }
      });
    }
}
Kabb5
  • 3,760
  • 2
  • 33
  • 55
  • This works for me, but why do you use double negative !! ? – awebdev Mar 18 '19 at 16:34
  • @awebdev - I use the double bang (!!) to cast truthy/falsey values into strict boolean types. In my code, event.url is a string, while !!event.url is a boolean that is evaulated by the if statement. If there is a value for event.url, then !!event.url will be true, otherwise, it will be false if there is not a value. See https://www.bennadel.com/blog/1784-using-double-not-operator-for-boolean-type-casting.htm – Kabb5 Mar 18 '19 at 17:15
  • Ahh that makes sense, I never took the time to learn why people use !!. Thanks! – awebdev Mar 18 '19 at 17:30
  • Another thing - how did you handle 301s? Did you configure this in your server? – awebdev Mar 19 '19 at 16:35
  • Won't SEO be affected unless a 301 status is returned? – awebdev Mar 19 '19 at 23:29
  • This was for an internal corporate app, so I did not care about SEO. My only concern was saved bookmarks. But you're right to take SEO into consideration for a public facing app. – Kabb5 Mar 20 '19 at 11:59
  • 5
    Note that this does not work if URL contains query string, like `/some/path?foo=1&bar=2`, because router encodes `?` and `&`. The `navigateByUrl` works better in this case: `this.router.navigateByUrl(event.url.replace('/#', ''));`. – ischenkodv May 11 '19 at 20:41
11

i don't know if is right way to do it. But you can do something like this : Goal is to subscribe to NavigationChange, then you check if your current route start by '#!', if yes, you redirect to the right route.

class AppComponent implement OnInit {
    constructor(router: Router) {
        //When url change, we check if actual url have #! on it, then we redirect to the route without it.
        router.events.subscribe((event: NavigationEvent): void => {
            this.url = router.url;
            if (this.url.match('/^#!/')) {          
              this.router.navigate(
                this.url.replace('#!','')
              );
            }
          }
        );

    }
}

Another approch more complicated in my opinion is to use custom "matcher". More information here :

https://github.com/angular/angular/issues/12442

Yanis-git
  • 7,737
  • 3
  • 24
  • 41