-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Blazor] Enable cancellation of navigation events #42877
Comments
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
Notes in advance of API review:
|
Unclear if |
API Review Notes:
Possible API based on feedback: namespace Microsoft.AspNetCore.Components;
public abstract class NavigationManager
{
+ public IDisposable RegisterLocationChangingHandler(Func<LocationChangingContext, ValueTask> locationChangingHandler);
+ protected ValueTask<bool> NotifyLocationChangingAsync(string uri, string? state, bool isNavigationIntercepted);
+ protected virtual void HandleException(Exception ex);
+ protected virtual void SetNavigationLockState(bool value);
}
namespace Microsoft.AspNetCore.Components.Routing;
+ public class LocationChangingContext
+ {
+ public string TargetLocation { get; }
+ public string? HistoryEntryState { get; }
+ public bool IsNavigationIntercepted { get; }
+ public CancellationToken CancellationToken { get; }
+ public void PreventNavigation();
+ }
+ public class NavigationLock : IComponent, IAsyncDisposable
+ {
+ public EventCallback<LocationChangingContext> OnBeforeInternalNavigation { get; set; }
+ public bool ConfirmExternalNavigation { get; set; }
+ } |
Yes, when a handler calls
I'm open to doing it this way. The possible API listed in the previous comment looks good to me. Does this need another formal API review before this issue can be |
That sounds good to me. We were just waiting on your feedback. API Approved! namespace Microsoft.AspNetCore.Components;
public abstract class NavigationManager
{
+ public IDisposable RegisterLocationChangingHandler(Func<LocationChangingContext, ValueTask> locationChangingHandler);
+ protected ValueTask<bool> NotifyLocationChangingAsync(string uri, string? state, bool isNavigationIntercepted);
+ protected virtual void HandleException(Exception ex);
+ protected virtual void SetNavigationLockState(bool value);
}
namespace Microsoft.AspNetCore.Components.Routing;
+ public class LocationChangingContext
+ {
+ public string TargetLocation { get; }
+ public string? HistoryEntryState { get; }
+ public bool IsNavigationIntercepted { get; }
+ public CancellationToken CancellationToken { get; }
+ public void PreventNavigation();
+ }
+ public class NavigationLock : IComponent, IAsyncDisposable
+ {
+ public EventCallback<LocationChangingContext> OnBeforeInternalNavigation { get; set; }
+ public bool ConfirmExternalNavigation { get; set; }
+ } |
One thing I missed earlier is that I also forget if we discussed whether we should seal |
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
API Review Notes:
API update approved. namespace Microsoft.AspNetCore.Components;
public abstract class NavigationManager
{
+ public IDisposable RegisterLocationChangingHandler(Func<LocationChangingContext, ValueTask> locationChangingHandler);
+ protected ValueTask<bool> NotifyLocationChangingAsync(string uri, string? state, bool isNavigationIntercepted);
+ protected virtual void HandleException(Exception ex);
+ protected virtual void SetNavigationLockState(bool value);
}
namespace Microsoft.AspNetCore.Components.Routing;
+ public sealed class LocationChangingContext
+ {
+ public LocationChangingContext(string targetLocation, string? historyEntryState, bool isNavigationIntercepted, CancellationToken cancellationToken);
+ public string TargetLocation { get; }
+ public string? HistoryEntryState { get; }
+ public bool IsNavigationIntercepted { get; }
+ public CancellationToken CancellationToken { get; }
+ public void PreventNavigation();
+ }
+ public sealed class NavigationLock : IComponent, IAsyncDisposable
+ {
+ public NavigationLock();
+ public EventCallback<LocationChangingContext> OnBeforeInternalNavigation { get; set; }
+ public bool ConfirmExternalNavigation { get; set; }
+ } |
There was more offline feedback about this API, so we're going to edit it hopefully one last time. API Review Notes:
Approved! namespace Microsoft.AspNetCore.Components;
public abstract class NavigationManager
{
+ public IDisposable RegisterLocationChangingHandler(Func<LocationChangingContext, ValueTask> locationChangingHandler);
+ protected ValueTask<bool> NotifyLocationChangingAsync(string uri, string? state, bool isNavigationIntercepted);
+ protected virtual void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context);
+ protected virtual void SetNavigationLockState(bool value);
}
namespace Microsoft.AspNetCore.Components.Routing;
+ public sealed class LocationChangingContext
+ {
+ public required string TargetLocation { get; init; }
+ public string? HistoryEntryState { get; init; }
+ public bool IsNavigationIntercepted { get; init; }
+ public CancellationToken CancellationToken { get; init; }
+ public void PreventNavigation();
+ }
+ public sealed class NavigationLock : IComponent, IAsyncDisposable
+ {
+ public NavigationLock();
+ public EventCallback<LocationChangingContext> OnBeforeInternalNavigation { get; set; }
+ public bool ConfirmExternalNavigation { get; set; }
+ } |
Is there a roadmap or plan for this feature? Forgive me if I'm new to the process. Thanks |
@garrettlondon1 Yes, this feature will ship in .NET 7. |
Background and Motivation
The ability to asynchronously delay/cancel navigations in Blazor has been a very popular ask from the community. Such a feature would allow Blazor developers to implement custom navigation prompts, save changes before navigating, or silently cancel navigations. There was a previous attempt to solve this problem in a limited fashion by using
window.confirm()
to display a built-in browser prompt that lets the user confirm navigations. This approach works well for simple cases, but community feedback indicated a desire for a more flexible mechanism, namely a "location changing" event enabling asynchronous callbacks to decide whether a navigation should be allowed or cancelled.Proposed API
We provide new APIs on
NavigationManager
to add and remove "location changing" handlers that run when an "internal" navigation is initiated. These handlers are given aLocationChangingContext
that provides information about the ongoing navigation in addition to aPreventNavigation()
method that prevents the navigation from continuing when invoked. There can be multiple handlers registered that get executed in parallel, where any handler may prevent the navigation.In addition, we also provide a
<NavigationLock/>
component that wraps the newNavigationManager
APIs. It includes an option for showing a browser prompt for confirming "external" navigations. Note that external navigations will not cause "location changing" handlers to get invoked. This is because thebeforeunload
event (used to determine if a prompt should display before navigating) must return synchronously, so the result from an asynchronous JS -> .NET callback cannot be utilized.Note: These changes have already been implemented in #42638. A follow-up PR will address any API review feedback.
Note: All of the following APIs are purely additive. I didn't use the
+ ...
diff format because then you don't get syntax highlighting.NavigationManager
is an existing class and all of the members listed here are new. The other two classes are entirely new.Usage Examples
<NavigationLock/>
ComponentNavigationManager
APIsUseful in cases where the lifetime of a navigation lock is not constrained to the lifetime of a specific Blazor component.
Risks
The implementation of this feature is quite involved (see #42638), and its asynchronous nature makes handling cases like overlapping navigations very non-trivial. However, we have ample test coverage for these scenarios, so we're reasonably confident in what we have. Code that doesn't use this feature won't be impacted by its existence; the entire "location changing" step is skipped unless there are handlers registered.
The text was updated successfully, but these errors were encountered: