So I've been playing around with Blazor WebAssembly and I can't figure out how to solve this problem. Basically, I have a NavMenu.razor page that will get an array of NavMenuItem asynchronously from a JSON file. That works fine. Now, what I'm trying to do is add an event listener to each of the anchors that are generated from the <NavLink>
tags in the below foreach loop.
The NavLink outside of that loop (the one not populated by the async function) successfully has the addSmoothScrollingToNavLinks() function applied to it correctly. The other NavLinks do not. It seems as if they are not yet in the DOM.
I'm guessing there's some weird race condition, but I don't know how to resolve it. Any ideas on how I might fix this?
NavMenu.razor
@inject HttpClient Http
@inject IJSRuntime jsRuntime
@if (navMenuItems == null)
{
<div></div>
}
else
{
@foreach (var navMenuItem in navMenuItems)
{
<NavLink class="nav-link" href="@navMenuItem.URL" Match="NavLinkMatch.All">
<div class="d-flex flex-column align-items-center">
<div>
<i class="@navMenuItem.CssClass fa-2x"></i>
</div>
<div class="mt-1">
<span>@navMenuItem.Text</span>
</div>
</div>
</NavLink>
}
}
<NavLink class="nav-link" href="#" Match="NavLinkMatch.All">
<div class="d-flex flex-column align-items-center">
This works!
</div>
</NavLink>
@code {
private NavMenuItem[] navMenuItems;
protected override async Task OnInitializedAsync()
{
navMenuItems = await Http.GetJsonAsync<NavMenuItem[]>("sample-data/navmenuitems.json");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await jsRuntime.InvokeVoidAsync("MyFunctions.addSmoothScrollingToNavLinks");
}
}
public class NavMenuItem
{
public string Text { get; set; }
public string URL { get; set; }
public string CssClass { get; set; }
}
}
index.html (underneath the webassembly.js script tag)
<script>
function scrollToTop() {
window.scroll({
behavior: 'smooth',
left: 0,
top: 0
});
}
window.MyFunctions = {
addSmoothScrollingToNavLinks: function () {
let links = document.querySelectorAll("a.nav-link");
console.log(links);
// links only has 1 item in it here. The one not generated from the async method
for (const link of links) {
link.addEventListener('click', function (event) {
event.preventDefault();
scrollToTop();
})
}
}
}
</script>