Blazor Tree: programmatically select node using load on demand

I have a data from a single self-referencing table (idboss may references to idcounty).

  class County
    {
        public int Idcounty
        public string Fullname 
        public int? Idboss 
    }

And I would like to select some node using loading on demand. I manually add data to tree-data variable but tree hierarchy brokens. All nodes are out of place.
Here's my code

<RadzenTree Data="@counties" Expand="@OnExpand" @bind-Value=@selected>
    <RadzenTreeLevel TextProperty="Fullname"  />
</RadzenTree>

@code {
    IEnumerable<County> counties;
    sausozuContext context;
    object selected;

    protected override async System.Threading.Tasks.Task OnInitializedAsync()
    {
        context = DbFactory.CreateDbContext();
        var result = await ProtectedSessionStore.GetAsync<int>("idcounty");
        var idcounty = result.Success ? result.Value : -1;
        if (context.Counties.FirstOrDefault(county => county.Idcounty == idcounty) != null)
        {
            var searchcounty = context.Counties.FirstOrDefault(county => county.Idcounty == idcounty);
            List<County> tempcounties = new List<County>();
            int? idboss = searchcounty.Idboss;
            while (idboss != null)
            {
                tempcounties.AddRange(context.Counties.Where(c1 => c1.Idboss == idboss).ToList());
                idboss = context.Counties.FirstOrDefault(c1 => c1.Idcounty == idboss)?.Idboss;
            }
            tempcounties.AddRange(context.Counties.Where(c1 => c1.Idboss == null).ToList());
            
counties = tempcounties.OrderBy(c => c.Idboss).ThenBy(c => c.Fullname).ToList();
            selected = counties.First(c => c.Idcounty == idcounty);
        }
        else
        {
            var idboss = context.Counties.OrderBy(c => c.Idboss).First().Idboss;
            counties = context.Counties.Where(c => c.Idboss == idboss).OrderBy(c => c.Idboss).ThenBy(c => c.Fullname).ToList();
        }
    }
    void OnExpand(TreeExpandEventArgs args)
    {
        var county = args.Value as County;
        if (county != null)
        {
            args.Children.Data = context.Counties.Where(c => c.Idboss == county.Idcounty).OrderBy(c=>c.Fullname);
            args.Children.TextProperty = "Fullname";
            args.Children.HasChildren = (county) => context.Counties.Any(c => c.Idboss == (county as County).Idcounty);
        }
    }

What I want:

And what I receives

Hi @alexd,

Did you check the data-binding demo? It shows a similar scenario - data-binding to the Employees table from the Northwind database. It has a self-referencing relationship EmployeeID -> ReportsTo. Here is how the configuration looks like:

<RadzenTree Data=@employees Style="height: 300px">
  <RadzenTreeLevel TextProperty="LastName" ChildrenProperty="Employees1" 
       Expanded=@ShouldExpand 
       HasChildren=@(e => (e as Employee).Employees1.Any()) 
   />
</RadzenTree>
1 Like

Whats this - Employees1?

It is the collection that contains the children of the current item. The Employee class is declared here.

1 Like

Thanks for your help! Rewrite my code and receive what i wanted.
Final version looks like that:

county.cs: added County1 and Counties1 properies

  class County
    {
        public int Idcounty
        public string Fullname 
        public int? Idboss 
        public County County1
        public ICollection<County> Counties1 
    }

sausozucontext.cs: added description about new properies

entity.HasOne(i => i.County1)
                       .WithMany(i => i.Counties1)
                       .HasForeignKey(i => i.Idboss)
                       .HasPrincipalKey(i => i.Idcounty);

.razor :

<RadzenTree Data="@counties" @bind-Value=@selected >
    <RadzenTreeLevel TextProperty="Fullname"  ChildrenProperty="Counties1" 
        Expanded=@ShouldExpand HasChildren=@(c => (c as County).Counties1.Any())/>
</RadzenTree>

@code {
    IEnumerable<County> counties;
    sausozuContext context;
    object selected;

    protected override async System.Threading.Tasks.Task OnInitializedAsync()
    {
        context = DbFactory.CreateDbContext();
        var result = await ProtectedSessionStore.GetAsync<int>("idcounty");
        var idcounty = result.Success ? result.Value : -1;
        var allcounties = context.Counties.Include(c => c.Counties1.OrderBy(c => c.Fullname)).ToList();
        counties = allcounties.Where(c => c.Idboss == null);
        if (context.Counties.Any(county => county.Idcounty == idcounty))
        {
            var searchcounty = context.Counties.First(county => county.Idcounty == idcounty);
            selected = searchcounty;
        }
    }

    bool ShouldExpand(object data)
    {
        var county = (data as County);
        var shouldexpand =  county.Idboss == null || county.Counties1.Any(c => c == selected);
        return shouldexpand;
    }
}
1 Like

One more question. Is there a way to autoscroll tree to selected?

At the moment this isn't possible out of the box. It can probably be done via JS interop though:

JSRuntime.InvokeVoidAsync("scrollToSelectedNode");

where scrollToSelectedNode is a JS function defined like this:

function scrollToSelectedNode() {
    document.querySelector('.rz-treenode-content-selected').scrollIntoView();
}
1 Like