I'm using Blazor WASM, and .Net 5.
I have a hierarchical data structure of an unknown depth. When my component loads, I show the first level of the data structure. When a user clicks one of the items, It should load the next level after loading the data from an API call. Then, you can continue to click until there are no more levels.
I thought I could do it with a self referencing component, but I am getting what appears to be an infinite recursive loop. I say that because when I run the application and click on something from the initial list, the application freezes.
A "Blade" is just some HTML markup with some event callbacks, and a "visible" property. a "ForEach" is a component iterator. It shouldn't be critical on how those work
The component is "ChildResourceList" and as you can see, it has a reference to itself.
The question is... how do you get that nested ChildResourceList to render on demand? Is there a different approach I could take without having to create things like GrandChildResouceList, GreatGrandchildResourceList, etc.
@inject IHttpClientFactory factory;
<Blade Visible="Visible" OnCloseButtonClick="OnClose" Title="@SelectedItem?.ResourceName">
<ForEach Context="r" Items="ResourceList">
<div @onclick="(() => SetChildItem(r.Item))">
@r.Item.ResourceName
</div>
</ForEach>
</Blade>
<ChildResourceList SelectedItem="ChildSelectedItem" Visible="ChildVisible"></ChildResourceList>
@code {
[Parameter] public EventCallback OnClose { get; set; }
[Parameter] public bool Visible { get; set; }
[Parameter] public Resource SelectedItem { get; set; }
Resource ChildSelectedItem { get; set; }
bool ChildVisible { get; set; }
List<Resource> ResourceList { get; set; } = new();
protected override async Task OnParametersSetAsync()
{
if (SelectedItem != null)
ResourceList = await GetResources();
}
async Task<List<Resource>> GetResources()
{
HttpClient client = factory.CreateClient(name: "api");
return await client.GetFromJsonAsync<List<Resource>>($"{Endpoints.Features.ResourceExplorer.GetChildResources}/{SelectedItem.ResourceUID.ToString()}");
}
void SetChildItem(Resource item)
{
ChildSelectedItem = item;
ChildVisible = true;
}
void OnChildClose()
{
ChildVisible = false;
ChildSelectedItem = null;
}
}
It does look like infinite recursion in the markup section. Your component will now always have a Child section. You need an @if() around the recursion:
@if (ChildSelectedItem != null)
{
<ChildResourceList SelectedItem="ChildSelectedItem" Visible="ChildVisible"></ChildResourceList>
}
You pass ChildVisible to the Blade (<Blade Visible="Visible") but the nested list is outside that Blade.