Aspnetcore: New event for NavigationManger

Created on 13 Oct 2019  路  21Comments  路  Source: dotnet/aspnetcore

The NavigationManager exposes

LocationChanged | An event that fires when the navigation location has changed.

but it does not expose a LocationChangingevent.

Such an event that occurs before navigation takes place is very useful because it allows the previous view to prepare for its deactivation, for example, to display a warning, cancel navigation or silently save changes.

Can you provide such a feature or is there already another way to achieve the above?

affected-medium area-blazor enhancement severity-major

Most helpful comment

It would be nice to cancel the navigation to. Use Case is that the user has unsaved changes and show an error to him so he is not leaving without save.

All 21 comments

Thank you for your feature request @Postlagerkarte.

We'll consider this feature during the next release planning period and update the status of this issue accordingly.

Not sure if this is what the OP was after with LocationChanging but it would be nice to have LocationChangeStart and LocationChangeEnd events. The use case for me would be to display a little progress bar to the user while navigation is happening.

It would be nice to cancel the navigation to. Use Case is that the user has unsaved changes and show an error to him so he is not leaving without save.

I hope that the team decides to give us a full set of methods, properties, and events to support navigation including easy access to the navigation history.

Such an improved version of the NavigationManager would certainly allow tracking the lifetime of a navigation via events like:

Navigated
NavigationProgress
NavigationFailed
NavigationStopped

Basically, hoping for an improved/adjusted version of the NavigationService 馃槂

Yes, it's great being able to develop an SPA application, but when the user can navigate away with changes unsaved, and no way to warn them, that's a serious flaw. You can use the javascript window.history.forward() trick in the _Hosts.html file to force the user back, but that refreshes the page losing all unsaved changes. For critical editing, I'm starting to use a state service to preserve changes, but it's a bit of a cludge to get round the problem.

If anyone can post suggestions on how best to implement this in SSB without waiting for Microsoft, please do so here.

And would be nice to have a way to handle history stack or just a simple "location.replace(url);"
Only way I found to do this currently, was with JS interop.
js like this:

window.controles_interop = {
    ...
    location_replace: function (url) {
        window.location.replace(url);
    }
};

then call:
await JSRuntime.InvokeVoidAsync("controles_interop.location_replace", $"/protocolo/{_id.Value}");

I mean something like this, so more practical:
_nav.NavigateTo($"/protocolo/{_id.Value}", replace: true);

@lucianotres We are adding that in a future update I think, but you don't need anything special to do that today, you can simply call JSRuntime.InvokeAsync("location.replace", url) and that will work

Are there any news about this issue's status?
May be there are some possibilities to override or extend functions from EventDelegator.ts or NavigationManager.ts or use own NavigationManager.cs realization with scripts duplicating above default? Sorry, if this question sounds kind of... elementary - i'm still novice at coding.

Hi,
I've been flat out on a project where I've resolved most of the issues I had. I'm just finishing testing and hoping to publish something covering the subject later this week/next week. My basic approach has been:

  1. Use the window.onbeforeunload event to warn the user that they are leaving the "application". You don't much control over this, but it works and users I have tested it on got the message.
    Place it in the _Host.cshtml.
  2. Use a scoped data service class to track the condition (dirty/clean) of the edited record.
  3. Use a scoped user session service class to temporarily hold page routing data while transitioning between routes. This also helps on the transition from New to Edit when first saving a record.
  4. Customize the standard router to check the save state of the record and either navigate or instruct the current page that the user is trying to leave and an "Are You Sure/Unsaved Data" action is required. Note that the NavigationManager only catches navigation changes and raises the LocationChanged event, the router registers with this event and does the actual work.

The key here is to get your head around what's actually going on, and what the various classes/objects are up to.

With this approach I no longer need to tamper with the back/forward history - the router handles "In Application" page changes and onbeforeunload warns the user if they are trying to navigate away.

Note that creating a customized version of the router isn't trivial. You will need to make copies of various other classes that are namespace restricted.

I'll put a post here when I have something polished enough to publish.

@ShaunCurtis thanks for reply!
I already implemented steps 1 and 2. Should be enough to override _OnLocationChanged_ event in Router class? And add there:
if (hasChanges) _jsRuntime.InvokeAsync("onbeforeHandler");
And then just change all classes referenced with _Router_. Or this is not so simple?
I have troubles with overriding _Router_, cause there are a lot of dependencies and idk how to register and use them after implementing. So I will look forward to see your approach (no matter how polished it is)!
Thanks for your attention!

@ShaunCurtis struggling with step 4 cannot wrap my head around it is there any other way right now? is solution for this still in progress?

I'm currently working on putting a working example together - literally as I write this. Hopefully I'll have something in the next day or two. This will include the "unwrapped" router code.

I've now published the routing on GitHub with a working example project. You can install the DLL via a Nuget Package (I hope!). The source code is all there in the GitHub repository.

https://github.com/ShaunCurtis/CEC.Routing

I've added a further project - CEC.FormControls - that uses the router with a more polished editor component similar to what I've been using in my projects. It uses enhanced Blazor InputBase Controls and the EditContext to manage editor control and routing. The Github repository is here:

https://github.com/ShaunCurtis/CEC.FormControls

I just put CEC.Routing in my project. Works quite nicely. Thanks @ShaunCurtis .

Hi @ShaunCurtis. Thanks! Will this library work for web assembly project as well? I need to rewrite URL to redirect URL to always remove or always add a port. For example: localhost:5001/authorize to localhost/authorize. Is this possible with your library?

Hi Nemtajo,
While the functionality isn't built in, you can download the code from the repository and add it. In your case you will need to update the _locationabsolute private property in either the OnLocationChanged or Refresh Methods in the RecordRouter class. However, if you are changing the URL then you aren't routing but doing normal navigation???

I found a much simpler method, In Startup.cs of the server project I added:

            app.UseStaticFiles(new StaticFileOptions()
            {
                OnPrepareResponse = (context) =>
                {
                    var request = context.Context.Request;
                    var response = context.Context.Response;
                    UrlRewriteUtils.AddPortIfLocalHost(request, response);
                }
            });

    public class UrlRewriteUtils
    {
        public static void AddPortIfLocalHost(HttpRequest request, HttpResponse response)
       {
           string url = request.GetDisplayUrl();
            if (url.Contains("localhost/authorize"))
            {
                var newUrl = url.Replace("localhost/authorize", "localhost:5001/authorize");
                response.Redirect(newUrl.ToString(), true);
            }
        }
    }

I used this as a reference: //https://stackoverflow.com/questions/51105799/how-do-i-force-https-redirect-on-static-files-in-asp-net-core-2-1

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

I believe this issue should receive more love from the Asp.net team. It is vital in a lot of Enterprise application that you manage when a certain window is closing without saving or something like that (In windows forms that is). But in our company's case, we are using Blazor to build the UI of our enterprise application. Now if i can not manage the state of the page being navigated away from and stop it if the user clicked on cancel, the user might accidentally click on a link or something that will move him away from the page losing all the important input he already entered (That he is not able in his line of business to obtain more than once).

Thank you @ShaunCurtis for your implementation, I think i will use it to take ideas to build my own.

Was this page helpful?
0 / 5 - 0 ratings