Solved: Reorder datagrid drag and drop row radzen

Continuing the discussion from Re-Order DataGrid Drag and Drop Row- Radzen:

Dears @enchev @iustin94
You can apply this easily. I will write an example code for one level for you, and it can be applied easily.


<RadzenDataGrid Data="@Employees" TItem="Employee" AllowFiltering="true" @ref="Grid">
    <Columns>
        <RadzenDataGridColumn TItem="Employee" Filterable="false" Sortable="true">
            <HeaderTemplate>
                 <div class="row">
                    <div class="col-3">
                        Name
                    </div>
                    <div class="col-3">
                        Job Title
                    </div>
                    <div class="col-3">
                        Salary
                    </div>
                    <div class="col-3">
                        Department
                    </div>
                </div>
            </HeaderTemplate>
            <Template Context="data">

                <div draggable="true" @ondragstart="@(() => OnDragStart(data))" ondragover="event.preventDefault()" @ondrop="@(() => OnDropAsync(data))" class="drag-and-drop">

                    <div class="row" style="cursor:move;">
                        <div class="col-3">
                            @data.Name
                        </div>
                        <div class="col-3">
                            @data.JobTitle
                        </div>
                        <div class="col-3">
                            @data.Salary
                        </div>
                        <div class="col-3">
                            @data.Department
                        </div>
                    </div>
                </div>

            
            </Template>
        </RadzenDataGridColumn>
    </Columns>
</RadzenDataGrid>

@code {
    RadzenDataGrid<Employee>? Grid;
    Employee? _selectedNode;
    Employee? _droppedNode;

    private List<Employee> Employees = new List<Employee>
{
    new Employee("Robin", 28, "Bangladesh", "Developer", 5000, "IT", new DateTime(2022, 1, 15), "robin@example.com", "123456"),
    new Employee("Tuhin", 27, "USA", "Designer", 4500, "Design", new DateTime(2021, 12, 10), "tuhin@example.com", "789012"),
    new Employee("Nion", 26, "Canada", "Manager", 6000, "Management", new DateTime(2022, 2, 20), "nion@example.com", "345678"),
    new Employee("Papon", 25, "Africa", "Engineer", 5500, "Engineering", new DateTime(2022, 3, 25), "papon@example.com", "901234"),
    new Employee("Faysal", 24, "Netherland", "Analyst", 4800, "Analysis", new DateTime(2022, 4, 30), "faysal@example.com", "567890"),
    new Employee("Nahid", 23, "China", "Coordinator", 4700, "Coordination", new DateTime(2022, 5, 5), "nahid@example.com", "234567"),
    new Employee("Nayem", 22, "Brazil", "Supervisor", 5200, "Supervision", new DateTime(2022, 6, 10), "nayem@example.com", "890123"),
    new Employee("John", 21, "Uganda", "Assistant", 4600, "Assistantship", new DateTime(2022, 7, 15), "john@example.com", "456789"),
};

    void OnDragStart(Employee employee)
    {
        _selectedNode = employee;
    }

    void OnDropAsync(Employee employee, bool isUp = false)
    {
        _droppedNode = employee;
        if (_selectedNode != null && _selectedNode != employee)
        {
           
            int originalIndex = Employees.IndexOf(_selectedNode);
            Employees.Remove(_selectedNode);
            int droppedIndex = Employees.IndexOf(_droppedNode); // Move to position after the target node

            // Check if moving downwards and adjust the index if needed
            if (originalIndex <= droppedIndex)
            {
                droppedIndex++; // Adjust index to account for the removed item
            }

            Employees.Insert(droppedIndex, _selectedNode);


            //..............
            // here put your code to save order in db if you want
            //  await UpdateAllNodesAsync(); // Update all nodes' positions
            //..............
            Grid!.Reload();
        }
    }
}



   public class Employee
   {
       public Employee(string name, int age, string country, string jobTitle, double salary, string department, DateTime hireDate, string email, string phoneNumber)
       {
           Name = name;
           Age = age;
           Country = country;
           JobTitle = jobTitle;
           Salary = salary;
           Department = department;
           HireDate = hireDate;
           Email = email;
           PhoneNumber = phoneNumber;
       }

       public string Name { get; set; } = string.Empty;
       public int Age { get; set; }
       public string Country { get; set; } = string.Empty;
       public string JobTitle { get; set; } = string.Empty;
       public double Salary { get; set; }
       public string Department { get; set; } = string.Empty;
       public DateTime HireDate { get; set; } = DateTime.Now;
       public string Email { get; set; } = string.Empty;
       public string PhoneNumber { get; set; } = string.Empty;
   }
1 Like

If you have more than one level, you can drag and drop within the same level,
and you can prevent rows from being Drag outside of the level. Here is the code for the update.

I mean more level in this example datagrid-selfref-hierarchy

    async Task OnDropAsync(Employee dataNode)
    {
        // to prevent Drag and drop outside of another level 
        if (_selectedNode.ParentID != dataNode.ParentID || _selectedNode.Level != dataNode.Level)
            return;

        _droppedNode = dataNode;


        if (_selectedNode != null && _selectedNode != _droppedNode)
        {
            if (_selectedNode.ReportsTo == null)  
            {
                int originalIndex = employees.IndexOf(_selectedNode);
                employees.Remove(_selectedNode);
                int droppedIndex = employees.IndexOf(_droppedNode); // Move to position after the target node

                // Check if moving downwards and adjust the index if needed
                if (originalIndex <= droppedIndex)
                {
                    droppedIndex++; // Adjust index to account for the removed item
                }

                employees.Insert(droppedIndex, _selectedNode);
             
                //..............
                // here put your code to save order in db if you want
                //  await UpdateAllNodesAsync(); // Update all nodes' positions
                //..............
            }
            else
            {
                //  this recurzion function to get parent for children GetParentNodeForChildren
                var _nodeChild = GetParentNodeForChildren(employees, _selectedNode.ParentID);
                 var parentNode = _nodeChild.FirstOrDefault(x => x.MenuId == _selectedNode.ParentID);
                if (parentNode != null)
                {
                    int originalIndex = parentNode.Children.IndexOf(_selectedNode);
                    parentNode.Children.Remove(_selectedNode);
                    int droppedIndex = parentNode.Children.IndexOf(_droppedNode);

                    if (originalIndex <= droppedIndex)
                    {
                        droppedIndex++;
                    }

                    parentNode.Children.Insert(droppedIndex, _selectedNode);
              
                // ..............
                // here put your code to save order in db if you want
                // await UpdateAllChildrenAsync(parentNode);// Update all children nodes' positions
                // ..............
       
                }
            }
        }
        await grid!.Reload();
    }
1 Like

Thanks @mjjalala, here is another simple example based on our first DataGrid demo:

@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore
@using System.Collections.ObjectModel

@inherits DbContextPage

<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true" AllowAlternatingRows="false" FilterMode="FilterMode.Advanced" AllowSorting="true" PageSize="5" AllowPaging="true" PagerHorizontalAlign="HorizontalAlign.Left" ShowPagingSummary="true"
    Data="@employees" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or" SelectionMode="DataGridSelectionMode.Single" @bind-Value=@selectedEmployees>
    <Columns>
        <RadzenDataGridColumn Title="#" Frozen="true" Sortable="false" Filterable="false" Width="50px" TextAlign="TextAlign.Center">
            <Template>
                <div class="rz-column-drag" ondragover="event.preventDefault()" draggable="true" style="cursor:grab;width:100%;height:100%;"
                     @ondragstart=@(args => draggedItem = context) @ondrop="@(args => Drop(args, context))" />
            </Template>
        </RadzenDataGridColumn>
       ...
    </Columns>
</RadzenDataGrid>

@code {
    ObservableCollection<Employee> employees;
    IList<Employee> selectedEmployees;

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        employees = new ObservableCollection<Employee>(dbContext.Employees);

        selectedEmployees = new List<Employee>(){ employees.FirstOrDefault() };
    }

    Employee draggedItem;

    void Drop(DragEventArgs args, Employee item)
    {
        employees.Remove(draggedItem);
        employees.Insert(employees.IndexOf(item), draggedItem);
    }
}

I will add this to our demos.

3 Likes

I'm pleased to hear that. Thank you @enchev.

Thanks a lot for the examples! I tried myself with the data grid but it seemed incompatible at first. If it does work than it will be amazing!

Here is the demo I've promised:

dg-dd

It's using RowRender event to attach directly to the row drag & drop logic.

3 Likes

Amazin! This feel cleaner and contained with the use of the OnRowRender funciton to add this functionality! Really nice

Thanks @enchev,
I have a minor note. When you want to drag an item from top to bottom for the element directly following it, the row order does not change.
To correct this, here is the code.

   args.Attributes.Add("ondrop", EventCallback.Factory.Create<DragEventArgs>(this, () =>
        {
        
           int originalIndex = employees.IndexOf(draggedItem);
            employees.Remove(draggedItem);
            int droppedIndex = employees.IndexOf(args.Data); // Move to position after the target node

           // Check if moving downwards and adjust the index if needed
           if (originalIndex <= droppedIndex)
            {
             droppedIndex++; // Adjust index to account for the removed item
            }
           employees.Insert(droppedIndex, draggedItem);

        }));

Sure @mjjalala, I've updated the demo.

1 Like

Thanks a lot @enchev.

I've added also one more example demonstrating how to drag & drop rows between two DataGrid components:

dg-dd-b

1 Like

Here is yet another demo with drag & drop however this time for the Tree component:

tree-dd

1 Like

Impressive!

Thank you to everyone who worked on this.

Mike

Hi!
I'm starting to use your framework and it's amazing, very impressive.
I'd like to implement the drag and drop function on a datagrid but not on the entire row, just on a single "drag" column... is it possible to make it work only on just a single column? It would be great!

You can enable DataGrid columns reorder as shown in this demo: