Click here to Skip to main content
15,884,176 members
Articles / Web Development / Blazor
Tip/Trick

Building a Folder Tree in Blazor

Rate me:
Please Sign up or sign in to vote.
4.75/5 (7 votes)
10 Feb 2022CPOL2 min read 14.7K   11   5
Implementation of a folder tree in front-end and back-end
This tip shows how-to create a Tree Folder / View in Blazor.

Introduction

Since Blazor is a relatively new technology, it may be hard to find new common features that can be found in other frameworks. That is the case of a recursive folder tree, which I could find only in "add my package to your project" solutions. The idea of this article is to share the front-end and the back-end of the solution, the whole code that you need to build a folder tree.

Image 1

Starting with the Back-end

First of all, I worked with a class called "Group", which will be the "Folder" (you can call it "Folder" if you want). It's a simple and common class. The only noticeable difference is that it has a "ParentGroupId" integer property to reference itself (yes, a group inside a group!), which is important to create the "folder inside a folder" effect that we need.

C#
public class Group
{
    public string Name { get; set; }
    public string? Description { get; set; }
    public int? ParentGroupId { get; set; }

    public Group ParentGroup { get; set; }
    public virtual List<Group> SubGroups { get; set; }
}

You can store it in SQL Server, MySQL, whatever. I will not cover how to use the SQL Server, or create the table. I will assume you can already save that class in a table and retrieve the information.

Recursive Method to Get All Folders/Groups Info

Inside your repository/controller/whatever you are using, you need to create a method to get all groups/folder recursively. In my case, I use a framework called Sparc from my company that does all that magic. In the end, I will post a link where you can get more information. This method is where you will have groups inside groups infinitely (no matter how many groups you have there). You can find the code below.

C#
public async Task<List<Group> GetGroups()
{
    // Get all groups from DB to save all the extra database calls
    var allGroups = await GroupRepository
        .Query
        .ToListAsync();

    // Start recursive function with the top of the tree
    LoadSubgroups(allGroups, null);

    allGroups = allGroups.Where(x => x.ParentGroupId == null).ToList();
    
    return allGroups;
}

private List<Group> LoadSubgroups(List<Group> allGroups, Group? parentGroup)
{
    var groups = allGroups.Where(x => x.ParentGroupId == parentGroup?.Id).ToList();

    foreach (var group in groups)
        group.SubGroups = LoadSubgroups(allGroups, group);

    return groups;
}

You can notice that the GetGroups() method calls the LoadSubgroups() method, and the LoadSubgroups() calls itself! The idea is that the LoadSubgroups() method calls itself recursively until there are groups to load.

Working on the Front-End With Components

We will have the same challenge we had on the backend: recursiveness! In this case, we need to use Blazor Components to create the recursive effect to create new HTML elements for each new Group/Folder that will be shown. I will assume that you can already get the Group/Folder information from the API.

GroupTree Component

First things first: we will need to create the GroupTree/FolderTree component:

C#
<div class="folder-tree-wrapper">
    <ul class="folder-tree">
        @foreach (var group in Groups)
        {
            <GroupItem Group="group" />
        }
    </ul>
</div>

@code {
    [Parameter] public List<GetGroupsResponse> Groups { get; set; }
}

You can notice that there is an HTML element that is not defined: the <GroupItem /> element! That will be another component (the child component) that will actually have the groups.

GroupItem Component

C#
<li>
    <div class="item-container">
        @if (Group.SubGroups.Any())
            {
                @if (Group.IsExpanded)
                {
                    <i class="material-icons expand-more" 
                     style="transform: rotate(180deg)" 
                     @onclick="ToggleGroup">expand_less</i>
                }
                else
                {
                    <i class="material-icons expand-more" 
                     style="transform: rotate(90deg)" 
                     @onclick="ToggleGroup">expand_less</i>
                }
            }
        <i class="material-icons" style="cursor: pointer; 
                 @(Group.SubGroups.Any() ? "" : "padding-left: 18px")">
                 @(allEntriesSelected ? "check_box" : "check_box_outline_blank")</i>
        <div style="display: inline-block" @onclick="ToggleGroup">
            <i class="material-icons">folder</i>
            <div style="display: inline-block">@Group.Name</div>
        </div>
    </div>

    @if (Group.SubGroups.Any() && Group.IsExpanded)
    {
        <ul>
        @foreach (var subGroup in Group.SubGroups)
        {
            <GroupItem Group="subGroup"/>
        }
        </ul>
    }
</li>

@code {
    [Parameter] public GetGroupsResponse Group { get; set; }
    public bool allEntriesSelected { get; set; }

    async Task ToggleGroup()
    {
        Group.IsExpanded = !Group.IsExpanded;
    }
}

And that is it! That's all you need to create a Folder/Tree solution with Blazor. The only thing you need to do now is to call the GroupTree component on the page you want to use it, like this:

C#
<GroupTree Groups="groups" />

If you have any questions or want to know more about the Sparc solution I talked about, just leave me a message! Either way, I can help you. :)

History

  • 10th February, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Brazil Brazil
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCode incomplete and does not work Pin
TrueJoshua11-Feb-24 8:13
TrueJoshua11-Feb-24 8:13 
QuestionWhat is GetGroupsResponse Pin
Davidw196911-Dec-23 16:22
Davidw196911-Dec-23 16:22 
QuestionInteresting techniques Pin
Roy Heath 202225-Jul-22 19:27
Roy Heath 202225-Jul-22 19:27 
QuestionBlazor Sample App Pin
Member 1325257911-Feb-22 13:51
professionalMember 1325257911-Feb-22 13:51 
AnswerRe: Blazor Sample App Pin
ferdrodrigues14-Feb-22 19:44
ferdrodrigues14-Feb-22 19:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.