Allow setting history.state when navigating#27198
Allow setting history.state when navigating#27198jasonaden wants to merge 5 commits intoangular:masterfrom
history.state when navigating#27198Conversation
history.state when navigating
|
You can preview 3dccc75 at https://pr27198-3dccc75.ngbuilds.io/. |
8859de5 to
e78a000
Compare
|
You can preview e78a000 at https://pr27198-e78a000.ngbuilds.io/. |
0fd82ac to
774916e
Compare
|
You can preview 774916e at https://pr27198-774916e.ngbuilds.io/. |
|
You can preview 0fd82ac at https://pr27198-0fd82ac.ngbuilds.io/. |
774916e to
45ee235
Compare
|
You can preview 45ee235 at https://pr27198-45ee235.ngbuilds.io/. |
|
LGTM The only thing I would add is that the commits here could benefit from additional info (e.g. a description of what the old behavior was and the motivation for changing it). One useful thing to add in each commit message in a multi-commit PR like this is a line or two about how the code in the commit is tested. |
packages/router/src/router.ts
Outdated
There was a problem hiding this comment.
what's the purpose of exposing this? if it's just to provide access to the previous url, then why not expose that directly as previousUrl?
There was a problem hiding this comment.
Because then we have to have 3 copies. The previousInitialUrl, previousExtractedUrl and previousFinalUrl. Also, we may add more data to this over time and exposing it this way means we don't need to bloat the object.
bf4ca6b to
8dd3a72
Compare
|
You can preview bf4ca6b at https://pr27198-bf4ca6b.ngbuilds.io/. |
|
You can preview 8dd3a72 at https://pr27198-8dd3a72.ngbuilds.io/. |
8dd3a72 to
5ac9f5a
Compare
|
You can preview 5ac9f5a at https://pr27198-5ac9f5a.ngbuilds.io/. |
…aged by Angular router
This value will get written to the `history.state` entry. FW-613 (related)
This value will get written to the `history.state` entry. FW-613 (related) Related to angular#24617
|
@jasonaden This feature looks really cool, thanks. However, as a user I am slightly confused about the lifespan of a "current navigation". If I subscribe to the queryParamMap, is it safe to rely on the current navigation's state as long as I stay synchronous (i.e., no switchMap's to some async observable)? I can't seem to find any documentation regarding the lifecycle of a single navigation. |
|
@jasonaden It does not seem to work, when I use getCurrentNavigation it always returns null. I leave the test that I have done: https://stackblitz.com/edit/angular-wgc6ou Thanks! |
|
@sky10p i got your example working: just moved the coding from ngOnInit to the constructor |
|
@fjauer And why does that work? Does the constructor not run before? Thanks for your time! |
|
I think there is a small bug - the // Navigations coming from Angular router have a navigationId state property. When this
// exists, restore the state.
const state = change.state && change.state.navigationId ? change.state : null;
setTimeout(
() => { this.scheduleNavigation(rawUrlTree, source, state, {replaceUrl: true, state }); }, 0);The workaround is to catch this._router.events.pipe(
filter(t =>t instanceof NavigationStart && (<NavigationStart>t).navigationTrigger == "popstate" ))
.subscribe((x: NavigationStart) => {
this._router.navigate([x.url], { state: x.restoredState });
}); |
|
@alecvolo Please open a (new) issue instead of commenting on closed ones. |
|
Maybe a stupid question? But was this nice feat merged in any official Angular Release? 7.2? Or does it wait for Angular 8? |
|
@f-aubert It has been released in Angular 7.2.0. Refer to the CHANGELOG file in the root directory of the repository to find changes. |
|
Thanks @Airblader for pointing me to the ChangeLog. I did miss it. I would have expected this Issue to be somehow tagged with 7.2.0, and the Routing Documentation to reflect this feature. But many thanks to all that contributed, it was greatly awaited and needed in my apps. |
|
Probably should create a new bug, but just wanted to see if this should work when receiving an error response in an interceptor and trying to pass the error message to an error component via the router's state object? I am getting a null object as @sky10p described from the call to getCurrentNavigation() and the code is in the constructor as @fjauer commented. |
|
Thanks for the feedback on this issue everyone. Good that it's useful for many, sorry about any problems with documentation or problems using the feature.
Internally, there is a reference to If someone wants to create a feature request for this with use cases, that would help clarify. Thanks! |
|
Why is this only implemented for the |
|
By saying this works only on the currently executing navigation, does that mean it shouldn't be used outside of the navigation lifecycle hooks? It doesn't work by the time ngInit is called in a component for example, getCurrentNavigation has reverted to null by that point. The stackblitz above shows it does work in a component constructor, but is that guaranteed? If it is used inside a service subscription in the constructor for example, will it have reverted to null by the time it is called? In general, is this approach supposed to replace the paramsMap.get method of passing params? I see it linked to a lot of those issues but the actual code here seems more related to the nav lifecycle hooks than giving the component access to the state? |
I'm not from the Angular team, but I'd confidently say »No«. This additional state has nothing to do with route or query parameters, and accessing those is always possible from an ActivatedRoute (even outside a navigation).
This is definitely an interesting question. I can't find any kindd of documentation or explanation as to what the design of on-going navigations and their lifecycle is. It's just a "it's on-going until it finished", which isn't very satisfying. What I can tell you is where I already use this feature: I subscribe to query parameters and inside that subscription I access the current navigation to check the state for a specific flag. |
By paramsMap.get I more meant the optional params that are passed via the matrix method in routing. This new functionality here is already being touted on StackOverflow as the new method for doing data passing via routing: https://stackoverflow.com/a/54365098/1669024 I can see why people would jump on it for optional params as it means they aren't getting tacked onto the URL (and are available to all segments of the route, not just the last as with the matrix method). |
Yes, for that state would be a solution*. I'd question whether you want to hide it from the URL, though, since encoding it on the URL makes the link reentrant (but I'm biased). *) As with everything, I'd evaluate it on a case-by-case basis, though. Personally I wouldn't go around and using history state for just about anything now. There's also implications to be considered such as state being kept when navigating back etc. |
And indeed that comes up in the SO comments :) In general though I think people are not liking those massive URLs... |
I tried it with mat-card, didn't work :( |
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
This feature adds a few capabilities. First, when a
popstateevent fires the value ofhistory.statewill be read and passed intoNavigationStart. In the past, only thenavigationIdwould be passed here.Additionally,
NavigationExtrashas a new public API calledstatewhich is any object that will be stored as a value inhistory.stateon navigation. For example, the object{foo: 'bar'}will be written tohistory.statehere:router.navigateByUrl('/simple', {state: {foo: 'bar'}});Additionally, the
NavigationExtrascan now be read during navigation. We're exposing a new typeNavigationthat provides information such as the navigation ID, target URL,NavigationExtraspassed to thenavigateByUrlmethod, and a string value indicating what triggered the navigation (popstate, imperative, etc).In order to read this
Navigationobject, use therouter.getCurrentNavigation()function. If there's no navigation currently executing, the value will benull. Continuing from the above example:These features are related to a series of issues regarding adding arbitrary data to navigations (#5217 #8515 #9804 #24617). Additionally, this PR closes #10248 for supporting setting
history.state.closes #25658