Search code examples
c#.net-corenavigationblazorblazor-webassembly

Blazor Navigationmanager cancel navigation on locationchanged


Question:

Is there a way on Blazor to cancel navigation?

Let's supose a siple a href like this:

<a href="/some/other/blazor/spa/page">Go</a>

I would like to cancel navigation (for example if we are editing a form)

What I have tried.

Via JS

I set onbeforeunload dom delegate via JSInterop:

window.onbeforeunload = function(){
        return 'Vols abandonar aquesta pàgina?';
      };

but blazor bypass it.

Via locationchanged

I tried unsuccessfully to intercept navigation on locationchanged event:

@implements IDisposable
@inject NavigationManager NavigationManager

...

protected override void OnInitialized()
{
    NavigationManager.LocationChanged += HandleLocationChanged;
}

private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
{
    // Cancel Navigation Here
}

public void Dispose()
{
    NavigationManager.LocationChanged -= HandleLocationChanged;
}

Solution

  • This functionality was added in .NET 7, the documentation can be found in the 'Handle/prevent location changes' section of the 'Routing and navigation' page.

    The example below from that documentation shows code to handle the navigation commencing (in the OnLocationChanging method) and then cancels that navigation (with context.PreventNavigation()) if the user tries to navigate to the counter page:

    NavigationManager Navigation
    
    <p>
        <button @onclick="@(() => Navigation.NavigateTo("/"))">
            Home (Allowed)
        </button>
        <button @onclick="@(() => Navigation.NavigateTo("/counter"))">
            Counter (Prevented)
        </button> </p>
    
    @code {
        private IDisposable? registration;
    
        protected override void OnAfterRender(bool firstRender)
        {
            if (firstRender)
            {
                registration = 
                    Navigation.RegisterLocationChangingHandler(OnLocationChanging);
            }
        }
    
        private ValueTask OnLocationChanging(LocationChangingContext context)
        {
            if (context.TargetLocation == "/counter")
            {
                context.PreventNavigation();
            }
    
            return ValueTask.CompletedTask;
        }
    
        public void Dispose() => registration?.Dispose(); }