2
votes

I have a routing configuration like so:

[
  {
    path: 'parent',
    component: ParentComponent,
    children: [
      {
        path: 'child-one',
        component: ChildOneComponent
      },
      {
        path: 'child-two',
        component: ChildTwoComponent
      }
    ]
  }
]

Inside the ParentComponent, I have a button that, when clicked, should add a query parameter to the current route/URL. I've found other answers that suggest this solution:

// inside ParentComponent
constructor(
  private router: Router,
  private route: ActivatedRoute
) { }

onButtonClick() {
  this.router.navigate([], {
    relativeTo: this.route,
    queryParams: { myparam: true },
    queryParamsHandling: 'merge',
  })
}

However, using this solution in the ParentComponent causes the navigation to be relative to the parent route, not the child route. So, for example, if the user is at the URL /parent/child-one and clicks the button, the browser will navigate to /parent?myparam=true instead of /parent/child-one?myparam=true.

Since this code runs in the top component of my application, I'd rather not get into the messy business of traversing the ActivatedRoute object looking for the appropriate route to pass to the relativeTo parameter, since there are a lot of edge cases that could pop up.

The Router object does provide the full, current URL in its url property, however, using that URL like so won't trigger a navigation event:

onButtonClick() {
  this.router.navigate([this.router.url], {
    queryParams: { myparam: true },
    queryParamsHandling: 'merge',
  })
}

Attempting the same thing with this.router.navigateByUrl also does not trigger a navigation event:

onButtonClick() {
  this.router.navigateByUrl(this.router.url, {
    queryParams: { myparam: true },
    queryParamsHandling: 'merge',
  })
}

Adding replaceUrl: true to the NavigationExtras object (the second parameter to navigateByUrl) also does not cause a navigation event.

2
You can try to use this.router.navigateByUrl insteadKasabucki Alexandr
Calling this.router.navigateByUrl with the current URL doesn't trigger a navigation event either.Trevor
Did you add { replaceUrl: true } parameter?Kasabucki Alexandr
Yes, I tried with and without the replaceUrl parameter.Trevor
for me this way is work ` this.router.navigate([], { queryParams: { myparam: true }, relativeTo: this.activatedRoute, fragment: this.activatedRoute.snapshot.fragment, queryParamsHandling:'merge', });` . And doesn't matter which component call itKasabucki Alexandr

2 Answers

1
votes

Okay, after much experimentation, I've come up with this solution:

onButtonClick() {
  const urlTree = this.router.parseUrl(this.router.url)
  urlTree.queryParams['myparam'] = 'true'
  this.router.navigateByUrl(urlTree)
}

While working on a simplified example, I wasn't able to reproduce the problem, so I've clearly hit an edge case in my project, that I haven't been able to track down fully.

After digging through the source code of navigateByUrl, it appears that the current URL and the new URL are compared and if they are determined to be the same, the navigation event is skipped. However, it looks like the NavigationExtras parameter isn't being considered in this comparison, which obviously matters if you're changing the query string parameters. The solution outlined above negates this flaw because the query parameters are integrated into the first parameter to navigateByUrl, which is the parameter used to determine if the new URL matches the old one. (See the source code here.)

1
votes

In 'app-routing.module.ts' file, add the following code:


    @NgModule({
      imports: [RouterModule.forRoot(routes, {
        paramsInheritanceStrategy: 'always'
      })],
      exports: [RouterModule]
    })