stygma
stygma

Reputation: 523

How can I handle an url with double slashes in angular?

For legacy reasons I am required to handle a route where there is potential for there to be two slashes back to back because there is an optional id in the path (e.g. /base//child/2). I can not change the url in anyway (like omitting the double slashes in favor of a secondary route). Is there anyway I can get the angular router to recognize this url and either redirect it or handle it?

This minimal stackblitz example shows the problem.

Upvotes: 1

Views: 3098

Answers (2)

PhineasJ
PhineasJ

Reputation: 342

It seems Angular can not parse url with double slash correctly, so the routing path mapping will not work. You can implement your own UrlSerializer instead of using the default DefaultUrlSerializer. Try to convert path "/base//child/1" to "/base/child/1".

import {UrlSerializer, UrlTree, DefaultUrlSerializer} from '@angular/router';
export class CustomUrlSerializer implements UrlSerializer {
  parse(url: any): UrlTree {
    let dus = new DefaultUrlSerializer();
    console.log(url);
    if(/\/\//.test(url)) {
      url = url.replace(/\/\//, '/');
    }
    return dus.parse(url);
  }
  serialize(tree: UrlTree): any {
    let dus = new DefaultUrlSerializer(),
    path = dus.serialize(tree);
    return path;
  }
}

Register it in app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { RouterModule, UrlSerializer } from '@angular/router';
import { CatchAllComponent } from './catch-all/catch-all.component';
import { InformedComponent } from './informed/informed.component';
import { CustomUrlSerializer } from './custom-url-serializer';

@NgModule({
  imports: [ 
    BrowserModule,
    FormsModule,
    RouterModule.forRoot([{
      path: 'base/child/:id',
      component: InformedComponent,
    }, {
      path: 'base/:parentId/child/:id',
      component: InformedComponent
    }, {
      path: '**',
      component: CatchAllComponent
    }])
  ],
  declarations: [ AppComponent, CatchAllComponent, InformedComponent ],
  providers: [
    { provide: UrlSerializer, useClass: CustomUrlSerializer }
  ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

Now the url with double slash "//" will be converted to "/". It will match the routing path "base/child/:id", so you can get the params and handle it.

Upvotes: 3

ihor.eth
ihor.eth

Reputation: 2420

I'd try with UrlMatcher something along these lines

matcher.ts

import { UrlSegment } from '@angular/router';

export function matcher(url:  UrlSegment[]) {
  console.log(JSON.stringify(url));
 return url.length === 1 && url[0].path === 'base' ? ({consumed: url}) : null;
}

routes

import  { matcher } from './matcher';

RouterModule.forRoot([{
  matcher: matcher,
  component: InformedComponent
}, {
  path: 'base/:parentId/child/:id',
  component: InformedComponent
}, {
  path: '**',
  component: CatchAllComponent
}])
]

Tried this with your stacknblitz and it works. Not sure but other options could be listening to router's navigation started event or a route guard.

Upvotes: 2

Related Questions