Standard and custom buttons together inside Blazor Syncfusion Grid

Standard and custom buttons together inside Blazor Syncfusion Grid

Today I would like to present to you a topic from outside the Power Platform and Dynamics 365 world. I suppose everybody knows (or has just heard about) Syncfusion company and their UI components suite for building web, desktop, and mobile applications. A few months ago, Syncfusion decided to make their product available under the community, free license. It is the offering for small teams and companies (details may be found here: https://www.syncfusion.com/sales/communitylicense).

I’ve started investigating possibilities that come together with the Syncfusion Blazor components pack. No surprise, I have started from investigating Syncfusion Blazor Grid possibilities. My goal was to create standard CRUD functionality for the entity named Section. This is standard functionality of the Syncfusion grid, and the only action I needed to implement was handlers dedicated to calling my REST API when CRUD operations were triggered by the grid. This is how I achieve this goal.

Code - version 1

Grid definition

<SfGrid @ref="Grid" DataSource="@Sections" AllowPaging="true" AllowSorting="true"
Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update", })">
    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="EditMode.Normal"></GridEditSettings>
    <GridPageSettings PageSize="10"></GridPageSettings>
    <GridEvents OnActionBegin="OnBeginHandler" TValue="Section"></GridEvents>
    <GridColumns>
        <GridColumn Field="Id" HeaderText="ID" Width="100" TextAlign="TextAlign.Right" IsPrimaryKey="true" AllowAdding="false"></GridColumn>
        <GridColumn Field="Name" HeaderText="Name" Width="200"></GridColumn>
        <GridColumn Field="Description" HeaderText="Description" Width="300"></GridColumn>
    </GridColumns>
</SfGrid>

Handling grid events

private async void OnBeginHandler(ActionEventArgs<Section> args)
{
    var data = args.Data;

    if (args.Action?.ToLower() == "add")
    {
        var section = SectionService.Insert(data);
        data.Id = section.Id;
        this.Grid.Refresh(); 
    }
    else if (args.Action?.ToLower() == "edit")
    {
        SectionService.Update(data);
    }
    if (args.Action?.ToLower() == "delete")
    {
        SectionService.Delete(data.Id);
    }
}

Things started to be a little more complicated where I wanted to mix standard CRUD functionalities together with custom buttons responsible for calling some non-standard logic. OnBeginHandler method was not called when clicking custom buttons added into buttons menu list. I decided to ask about it in one of the popular AI services. This is what I’ve got as a response.

Code - Version 2

Grid definition

<SfGrid @ref="Grid" DataSource="@Sections" AllowPaging="true" AllowSorting="true"
        Toolbar="@toolbarItems">
    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="EditMode.Normal"></GridEditSettings>
    <GridPageSettings PageSize="10"></GridPageSettings>
    <GridEvents OnActionBegin="OnBeginHandler" TValue="Section" onToolbarClick="OnToolbarClickHandler"></GridEvents>
    <GridColumns>
        <GridColumn Field="Id" HeaderText="ID" Width="100" TextAlign="TextAlign.Right" IsPrimaryKey="true" AllowAdding="false"></GridColumn>
        <GridColumn Field="Name" HeaderText="Name" Width="200"></GridColumn>
        <GridColumn Field="Description" HeaderText="Description" Width="300"></GridColumn>
    </GridColumns>
</SfGrid>

Handling grid events

private List<string> toolbarItems = new()
{
    "Add", "Edit", "Delete", "Update", "Cancel", "DoSomething"
};

private async void OnToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
{
    if (args.Item.Text == "DoSomething")
    {
        //TODO: This is the place where I would like o have my custom logic applied
    }
}

private async void OnBeginHandler(ActionEventArgs<Section> args)
{
    var data = args.Data;

    if (args.Action?.ToLower() == "add")
    {
        var section = SectionService.Insert(data);
        data.Id = section.Id;
        this.Grid.Refresh();
    }
    else if (args.Action?.ToLower() == "edit")
    {
        SectionService.Update(data);
    }
    if (args.Action?.ToLower() == "delete")
    {
        SectionService.Delete(data.Id);
    }
}

What I didn’t like was this code was using buttons’ Text properties to identify which one was clicked. Finally, I have prepared another modification that uses button identifiers instead of hardcoded labels.

Code - Version 3

Grid definition

Grid definition is the same as in the previous example.

Handling grid events

However, handling grid events and toolbar items definition looks a little different this time:

private List<ToolbarItem> toolbarItems = new()
{
    new ToolbarItem { Id = AddButtonId, Text = "Add", PrefixIcon = "e-add"  },
    new ToolbarItem { Id = EditButtonId, Text = "Edit", PrefixIcon = "e-edit"  },
    new ToolbarItem { Id = DeleteButtonId, Text = "Delete", PrefixIcon = "e-delete" },
    new ToolbarItem { Id = UpdateButtonId, Text = "Update", PrefixIcon = "e-update" },
    new ToolbarItem { Id = CancelButtonId, Text = "Cancel", PrefixIcon = "e-cancel"  },
    new ToolbarItem { Id = DoSomethingButtonId, Text = "DoSomething" }
};

private async void OnToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
{
    if (args.Item.Id == AddButtonId)
    {
        await Grid.AddRecordAsync();
    }
    else if (args.Item.Id == EditButtonId)
    {
        await Grid.StartEditAsync();
    }
    else if (args.Item.Id == DeleteButtonId)
    {
        await Grid.DeleteRecordAsync();
    }
    else if (args.Item.Id == UpdateButtonId)
    {
        await Grid.EndEditAsync();
    }
    else if (args.Item.Id == CancelButtonId)
    {
        await Grid.CloseEditAsync();
    }
    if (args.Item.Id == DoSomethingButtonId)
    {
        //TODO: This is the place where I would like o have my custom logic applied
    }
}

private async void OnBeginHandler(ActionEventArgs<Section> args)
{
    var data = args.Data;

    if (args.Action?.ToLower() == "add")
    {
        var section = SectionService.Insert(data);
        data.Id = section.Id;
        this.Grid.Refresh();
    }
    else if (args.Action?.ToLower() == "edit")
    {
        SectionService.Update(data);
    }
    if (args.Action?.ToLower() == "delete")
    {
        SectionService.Delete(data.Id);
    }
}

You may found all the presented code in my GitHub profile. Due to some reasons server-side REST API code has been replaced by the stubs working inside client web assembly.