3

I am passing dynamically generated URL with queryParams inside [routerLink] and it breaks routes.

i.e: this.url = '/question/ask?details=1'

<a [routerLink]="url"> {{ data.name }}</a>

When we mouseover it looks something like this #/question/ask%3Fdetails%3D1 and breaks when we click.

P.S: Since I am passing dynamic URLs so passing [queryParams] separetly not possible however this works:

<a [routerLink]="/question/ask" [queryParams]={details: 1}> {{ data.name }}</a>

Any solution we can pass a complete URL with queryParams inside [routerLink]?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Kamran Khatti
  • 3,754
  • 1
  • 20
  • 31

2 Answers2

4

Short Answer:

Whatever you pass inside routerLink directive will end up calling encodeURI function on value that have been passed.


Long Answer

This happens because when you directly pass whole url inside routerLink it eventually call serializeUrl method of routerLink directive. Which call serialize method of urlSerializer. The implementation of serialize method looks like below. code link here

serialize(tree: UrlTree): string {
    const segment = `/${serializeSegment(tree.root, true)}`;
    const query = serializeQueryParams(tree.queryParams);
    const fragment =
        typeof tree.fragment === `string` ? `#${encodeUriFragment(tree.fragment !)}` : '';

    return `${segment}${query}${fragment}`;
}

export function encodeUriFragment(s: string): string {
    return encodeURI(s);
}

Possible workaround to solve this issue could be, decode the URL by using angular Router's inbuilt method called as parseUrl method. Which basically help you to find root of the URL and params, queryParams, etc.

Component

@Component({
  ...
})
export class AppComponent {
  name = 'Angular 6';
  url: any;
  formattedUrl: any;
  params: any = {};

  constructor(private router: Router) {
  }

  ngOnInit() {
    this.urlDecoder();
  }

  urlDecoder() {
    this.url = '/a?i=1 a';
    let parsedUrl = this.router.parseUrl(this.url);
    console.log(parsedUrl)
    const g: UrlSegmentGroup = parsedUrl.root.children[PRIMARY_OUTLET];
    const s: UrlSegment[] = g.segments;
    this.formattedUrl = `${s.map(p => p.path).join('/')}`; // this is required to combine all continued segment
    this.params = parsedUrl.queryParams;
  }
}

Html

<a [routerLink]="formattedUrl" [queryParams]="params">
  Link Here
</a>

Demo Stackblitz

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • cant we use `decodeURI` to decode URL so that it decode special chars. Thanks for that detail ans though. – Kamran Khatti Jul 10 '18 at 18:34
  • @KamranKhatti no we can't, rather you can pass your own urlSerializer implementation by overriding `serialize` method, but rather I'd prefer you to do it in this way. Did you check the stackblitz? – Pankaj Parkar Jul 10 '18 at 18:36
  • I did but I think you missed something, its not rendering the value of `formattedUrl` – Kamran Khatti Jul 10 '18 at 18:42
  • @KamranKhatti give me a moment. Just fixing missing part. Thanks for heads up – Pankaj Parkar Jul 10 '18 at 18:45
  • That same solution I already did I am looking for any short solution which I am thinking angular should have coz the requirement is a regular not a special one so there should be a better solution instead of hacky or workaround. Thanks for your ans I am upvoting it though. – Kamran Khatti Jul 10 '18 at 19:30
  • @KamranKhatti better way to solve this solution could be create a component / directive, that will do all work for you :) – Pankaj Parkar Jul 10 '18 at 19:36
  • @KamranKhatti simplified version could look like this, please check [stackblitz](https://stackblitz.com/edit/angular-mdcdxc?file=src%2Fapp%2Fapp.component.html). I'd love to update answer if you like it. – Pankaj Parkar Jul 10 '18 at 19:48
  • @KamranKhatti did you get chance to check the updated stackblitz? – Pankaj Parkar Jul 11 '18 at 05:36
  • Yeah I did but that is pretty much same I am trying to avoid playing with URL (parsing and separating queryParam etc), lets see if I get a better option still trying to get a better one otherwise this will be the ultimate solution. – Kamran Khatti Jul 11 '18 at 09:01
  • Have a look at this one: https://stackoverflow.com/questions/36597832/angular2-routerlink-breaks-routes-by-replacing-slash-with-2f – Kamran Khatti Jul 11 '18 at 09:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/174782/discussion-between-kamran-khatti-and-pankaj-parkar). – Kamran Khatti Jul 11 '18 at 09:21
-1

Try this:

this.url = ['/question', 'ask']; //Maybe without slash: ['question', 'ask']
this.query = {details: 1};

Html:

<a [routerLink]="url" [queryParams]="query">Somewhere</a>