Update Record field on RowDropped

Hello!

I have a Grid with a simple model: Id, SortOrder, and Name. When a row is dropped to a new location, I would like to update all of the records in the Grid such that SortOrder = RowIndex of each record. Then save back to the db.

For example,  Before Drop

SO  NAME
1 - A
2 - B
3 - C

After dropping row 1 between 2 and 3

SO  NAME
1 - B
2 - A
3 - C

Is there a way to do that?


Kind regards,

Judi Smith


4 Replies

PS Prathap Senthil Syncfusion Team May 7, 2024 01:25 PM UTC

Hi Judi,


Based on your requirements, we suggest the following possible approach to fulfill your needs using the RowDropped event to update the sort order index. Please refer to the code snippet and sample provided below for your reference.

 

 

<SfGrid @ref="Grid" TValue="Order" AllowRowDragAndDrop="true" DataSource="@Orders">

    <GridEvents RowDropped="RowDropHandler" TValue="Order"></GridEvents>

    <GridColumns>

        <GridColumn Field=@nameof(Order.OrderID) HeaderText="ID" IsPrimaryKey="true" TextAlign=" Syncfusion.Blazor.Grids.TextAlign.Right" Width="120"></GridColumn>

        <GridColumn Field="@nameof(Order.SortOrder)"></GridColumn>

        <GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>

         </GridColumns>

</SfGrid>

 

@code {

    public List<Order> Orders { get; set; }

 

    SfGrid<Order> Grid { get; set; }

 

    public void RowDropHandler( Syncfusion.Blazor.Grids.RowDroppedEventArgs<Order> args)

    {

        var Datas = Grid.GetCurrentViewRecordsAsync().Result;

 

        foreach (var data in Datas)

        {

            var index = Grid.GetRowIndexByPrimaryKeyAsync(data.OrderID).Result;

            if(index != data.SortOrder)

            {

                data.SortOrder = index;

                Grid.UpdateRowAsync(index, data);

            }

        }

    }

}


Sample:
https://blazorplayground.syncfusion.com/embed/hZVTXeDmTGlGwUgz?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5

Reference:
https://blazor.syncfusion.com/documentation/datagrid/events#rowdropped
https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_UpdateRowAsync_System_Int32__0_
https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_GetCurrentViewRecordsAsync

Regards,
Prathap Senthil



JS Judi Smith May 7, 2024 03:29 PM UTC

Thank you for your reply. I have implemented as you suggested. However, it does not work as you can see in this video: https://www.loom.com/share/7a6d7b55ef2646ab85fd7baa9486950e?sid=12539aac-7a22-4636-bf73-426259014637.

When tracing at a breakpoint, I see there is a null reference exception, but that does not throw the error to the ActionFailure method.

This is the error:

System.NullReferenceException: Object reference not set to an instance of an object.
  at StudioPlanner.Client.Pages.Settings.SettingsComponents.MembershipCategoriesComponent.RowDroppedHandler(RowDroppedEventArgs`1 args) in /Users/judismith/Projects/StudioPlanner/StudioPlannerWASM/StudioPlanner/Client/Pages/Settings/SettingsComponents/MembershipCategoriesComponent.razor:line 42
   at System.Object.InvokeStub_MembershipCategoriesComponent.RowDroppedHandler(Object , Span`1 )
   at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

Here is the code:

@using StudioPlanner.Client.Pages.Shared
@using StudioPlanner.Shared.Models.LookUpCodes
@using FailureEventArgs = Syncfusion.Blazor.Grids.FailureEventArgs

<h3>Membership Categories</h3>
<SfGrid TValue="MembershipCategory" ref="@MembershipCategoryGrid" AllowSorting="true" AllowExcelExport="true" AllowRowDragAndDrop="true"
AllowReordering="true" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" })">
<GridEditSettings AllowAdding="true" AllowDeleting="true" AllowEditing="true" AllowEditOnDblClick="false"></GridEditSettings>
<SfDataManager Url="api/membershipcategory" Adaptor="Adaptors.WebApiAdaptor"></SfDataManager>
<GridSortSettings>
<GridSortColumns>
<GridSortColumn Field="@nameof(MembershipCategory.SortOrder)" Direction="SortDirection.Ascending"></GridSortColumn>
</GridSortColumns>
</GridSortSettings>
<GridColumns>
<GridColumn Type="ColumnType.CheckBox" Width="50"/>
<GridColumn Field="@nameof(MembershipCategory.Id)" HeaderText="Membership Category ID" IsPrimaryKey="true" IsIdentity="true" TextAlign="TextAlign.Right" Visible="false"/>
<GridColumn Field="@nameof(MembershipCategory.SortOrder)"/>
<GridColumn Field="@nameof(MembershipCategory.Name)"></GridColumn>
<GridColumn HeaderText="Edit">
<GridCommandColumns>
<GridCommandColumn Type="CommandButtonType.Edit" ButtonOption="@(new CommandButtonOptions() { IconCss = "e-icons e-edit", CssClass = "e-flat" })"/>
</GridCommandColumns>
</GridColumn>
</GridColumns>
<GridEvents TValue="MembershipCategory" OnActionFailure="@ActionFailure" RowDropped="RowDroppedHandler"/>
</SfGrid>

@code {
[CascadingParameter]
public ProcessError Error { get; set; }

private SfGrid<MembershipCategory> MembershipCategoryGrid;

private void ActionFailure(FailureEventArgs eventArgs)
{
Error.ProcessThisError("Error in Membership Category listing: " + eventArgs.Error.Message);
}

private void RowDroppedHandler(RowDroppedEventArgs<MembershipCategory> args)
{
var categories = MembershipCategoryGrid.GetCurrentViewRecordsAsync().Result;
foreach(var category in categories)
{
var index = MembershipCategoryGrid.GetRowIndexByPrimaryKeyAsync(category.Id).Result;
if (index + 1 != category.SortOrder)
{
category.SortOrder = index + 1;
MembershipCategoryGrid.UpdateRowAsync(index, category);
}
}
}
}


Thank you in advance for your help.

Kind regards,

Judi Smith



JS Judi Smith May 7, 2024 04:20 PM UTC

I fixed the problem with the reference to the grid.

Further, I have tried to update the RowDroppedHandler method to an async method as demonstrated in the documentation for GetCurrentViewRecordsAsync(), I made the RowDroppedHandler an async task and awaited the call to GetCurrentViewRecordsAsync.

With and without async/await, as I trace the program, what appears to be happening is that SortOrder is set with the RowIndex prior to the change in the row index of the row being dropped. 



PS Prathap Senthil Syncfusion Team May 8, 2024 12:29 PM UTC

Based on the problem you reported, we suggest using the Async task method. We would like to clarify that the RowDropped event will be triggered when row elements are dropped on the target element. This is the default behavior. So, when using the solution below, once the target element is dropped, the sort index will change. Meanwhile, we don't face the problem of SortOrder with the RowIndex before the row index of the dropped row changes. Please refer to the code snippet and sample below for your reference.

public async Task   RowDropHandler(Syncfusion.Blazor.Grids.RowDroppedEventArgs<Order> args)

{

 

 

     var Datas = await Grid.GetCurrentViewRecordsAsync();

 

     foreach (var data in Datas)

     {

         var index = await Grid.GetRowIndexByPrimaryKeyAsync(data.OrderID);

         if (index != data.SortOrder)

         {

             data.SortOrder = index;

             await Grid.UpdateRowAsync(index, data);

         }

     }

}


Sample: https://blazorplayground.syncfusion.com/embed/rNLJtIXbKiWsIzBe?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5


Loader.
Up arrow icon