I have a component that updates options on the NavMenu. I want to refresh it. This is what I have tried:
_categoriesRepository.Create(Category);
await _jsRuntime.ToastrSuccess("Category Created");
_navigationManager.NavigateTo($"/category/{fileType}/{fileRoot}", true);
This actually works but the await on the toastr notification is obliterated by the page refresh, so I thought:
_categoriesRepository.Create(Category);
_navigationManager.NavigateTo(_navigationManager.Uri, true);
await _jsRuntime.ToastrSuccess("Category Created");
_navigationManager.NavigateTo($"/category/{fileType}/{fileRoot}");
But the does not return me to the right page. It leaves me on the page I am on.
Ideally, I'd like to just refresh the NavMenu component. Is this possible? This way I could refresh the component and then navigate to the page that I wish to and then the toaster would work as expected. Or is there another way to refresh the entire page and then show the toaster notification and then navigate to the correct page?
You are using brute force to refresh your display:
_navigationManager.NavigateTo($"/category/{fileType}/{fileRoot}", true);
Resets the SPA. And destroys the Toast!
To do this properly your service needs to look something like this.
Note:
public class NavigationService
{
private List<NavigationItem> _links = new List<NavigationItem>();
public IEnumerable<NavigationItem> Links => _links.AsEnumerable();
public event EventHandler? LinksChanged;
public void AddLink(NavigationItem link)
{
if (!_links.Any(item => item == link))
{
_links.Add(link);
this.LinksChanged?.Invoke(this, EventArgs.Empty);
}
}
}
public record NavigationItem(string Title, string Url);
Update NavMenu
to inject the service and register the LinksChanged
event to update the component.
Note:
OnInitialized
.IDisposable
and unregisters the event handler in Dispose
.@inject NavigationService NavigationService
@implements IDisposable
//...
@foreach(var link in this.NavigationService.Links)
{
<div class="nav-item px-3">
<NavLink class="nav-link" href="@link.Url">
<span class="oi oi-list-rich" aria-hidden="true"></span> @link.Title
</NavLink>
</div>
}
</nav>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
protected override void OnInitialized()
=> this.NavigationService.LinksChanged += this.OnNavChanged;
private void ToggleNavMenu()
=> collapseNavMenu = !collapseNavMenu;
private void OnNavChanged(object? sender, EventArgs e)
=> this.InvokeAsync(StateHasChanged);
public void Dispose()
=> this.NavigationService.LinksChanged -= this.OnNavChanged;
}
And the demo page to add the link (once):
@page "/"
@inject NavigationService NavigationService
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<div>
<button class="btn btn-dark" @onclick=AddLink>Add Link</button>
</div>
@code {
private void AddLink()
=> this.NavigationService.AddLink(new("Fred", "/Counter"));
}