This repo contains the code that demonstrates the features of the BlazrRouter and BlazrNavigationManager in the Blazor.Routing library. It's principle purpose is to provide functionality to turn routing/navigation on and off. The principle application of this functionality is in edit forms to stop navigation when the form state is dirty.
It's a culmination of many iterations of my own work and code with a contributions from elsewhere including a NavigationManager implementation by Adam Stevenson documented in his Github Repo here. There's a significant amount of Microsoft AspnetCore repository "lifted" code to rebuild the Blazor Router.
The Repo is structured using my Blazor Clean Design Template. It's Net6.0, can be run in either Web Assembly or Server modes - it's the same code base. Just set the appropriate Startup project.
Go to the "Edit Form Demo" page to see the form/page locking concepts in action. Click on the button to toggle the form from dirty to clean and then attempt to navigate away from the page by clicking links, using the back button, F5 or clicking on favourites. There's also some cheeky feedback messages to show the events.
In both Web Assembly and Server all in-browser navigation events are captured by the Blazor JS code. However, they surface very differently in the NetCore libraries.
In Web Assembly the JS navigation event code calls the NotifyLocationChanged JsInterop registered method. This gets the current instance of WebAssemblyNavigationManager and calls SetLocation. Note this gets the instance of WebAssemblyNavigationManager directly through it's Instance static method, not through the DI container.
public static class JSInteropMethods
{
[JSInvokable(nameof(NotifyLocationChanged))]
public static void NotifyLocationChanged(string uri, bool isInterceptedLink)
{
WebAssemblyNavigationManager.Instance.SetLocation(uri, isInterceptedLink);
}
}In Server the calls get transferred over the SignalR connection and are handled by the ComponentHub
public async ValueTask OnLocationChanged(string uri, bool intercepted)
{
var circuitHost = await GetActiveCircuitAsync();
if (circuitHost == null)
return;
_ = circuitHost.OnLocationChangedAsync(uri, intercepted);
}This calls the CircuitHost method:
public async Task OnLocationChangedAsync(string uri, bool intercepted)
{
await Renderer.Dispatcher.InvokeAsync(() =>
{
var navigationManager = (RemoteNavigationManager)Services.GetRequiredService<NavigationManager>();
navigationManager.NotifyLocationChanged(uri, intercepted);
});
}
//lots of code missing to only show the relevant linesThis time it gets the registered NavigationManager service and casts it as a RemoteNavigationManager object before calling the NotifyLocationChanged method.
The demo can be run in either Web Assembly or Server modes.
Set Blazr.Demo.Routing.Server.Web as the startup project to run the Server version.
Set Blazr.Demo.Routing.WASM.Web as the startup project to run the Web Assembly version.
-
Add Blazr.Routing to the solution, and add project references where required.
-
Change out the
RouterinApp.razor
@namespace Blazr.UI
<BlazrRouter AppAssembly="@typeof(App).Assembly">
......
</BlazrRouter>- Add the new Navigation Manager service
services.AddBlazrNavigationManager();- Add the JS reference to the SPA startup page - __Hosts.html, __Layout.html or index.html .
<script src="_content/Blazr.Routing/site.js"></script>-
Review
EditForm.razorfor an implementation demo of how to control theBlazrNavigationManagerlock state. -
Add the
PageLockercomponent to the page.
@page "/EditForm"
@namespace Blazr.UI
<PageLocker />
//.....