60

How to replace a history instead a pushing a new in angular 2's new router (rc.1)?

For example Im in a question list (/questions) opening a new modal in a new route (/questions/add), and after adding a new question I go to the question view (/questions/1). If I press back I would like to go to the /questions instead of /questions/add

pleerock
  • 18,322
  • 16
  • 103
  • 128
  • have you tried 'canDeactivate' guard for your route '/questions/1'? Just check the desired destination, if it is '../add', redirect to '/questions'? Or implement 'canActivate' for '../add' route instead.. – Oleg Barinov Aug 11 '16 at 08:29
  • too much complicated. i have hundred of places where I need this behaviour and guards with redirects are just monkey patches that will produce lot of code – pleerock Aug 11 '16 at 08:32

2 Answers2

117

If you use

router.navigate

And then

location.replaceState

With the exact same path, you can trigger changes that usually happen, as well as replacing the history.

For example, in your case:

this.router.navigate(['questions/1']);
this.location.replaceState('questions/1');

If you need to add parameters to the route, you can create the url for location using

router.serializeUrl(router.createUrlTree(/* what you put in your router navigate call */));

In your example:

this.router.navigate(['questions/1', {name:"test"}]);
this.location.replaceState(this.router.serializeUrl(this.router.createUrlTree(['questions/1', {name:"test"}])));

Update

It seems the angular router now comes with a replace url option. In your example:

this.router.navigate(["questions/1"], {replaceUrl:true});

Update 2

There is a current issue where multiple navigations done in a short amount of time may not replace the URL correctly. As a temporary workaround, wrap the navigate function in a timeout to get each to fire in a separate cycle:

setTimeout(()=>{
    this.router.navigate(["questions/1"], {replaceUrl:true});
});
Jason
  • 1,221
  • 1
  • 8
  • 4
  • 3
    Note: For [routerLink](https://angular.io/api/router/RouterLink) directives, you can add a `replaceUrl` attribute to the element for the same effect. – dokkaebi Oct 24 '17 at 17:01
  • 3
    The only caveat to using `router.navigate` and `{ replaceUrl: true }` is it will register another navigation event. If you are listening to navigation events (eg, `NavigationEnd`) and don't want two events to fire, `location.replaceState` will do the trick. – Alan Nov 01 '17 at 14:27
  • Thanks, @Jason for your Update 2 and specifying the issue we have in angular. It was able to resolve my case in Angular 6 by using setTimeout(). – Mohd Belal Dec 18 '18 at 09:04
  • Note that `{replaceUrl: true}` is also available as an extra option to `router.createUrlTree()`, which means you can use it when returning an `Observable` from a `CanActivate` guard (instead of having to resort to explicit router navigation). – Mark Peters Jan 22 '20 at 16:54
  • https://stackoverflow.com/questions/35618463/change-route-params-without-reloading-in-angular-2 – RajeshKdev Sep 13 '21 at 13:47
5

You want to use replaceState from the Locations class

https://angular.io/docs/ts/latest/api/common/index/Location-class.html#!#replaceState-anchor

Gary
  • 421
  • 3
  • 4