Your search did not match any results.

Data Grid - Remote Reordering

This demo shows how to use drag-and-drop to reorder records stored on the server. This functionality requires that records' order indexes are in an individual data field (OrderIndex in this demo) and sorted against that field.

Row drag-and-drop is configured in the [rowDragging][3] object. Set [allowReordering][2] to true to enable this feature. When a row is dropped, the [onReorder][0] event handler is called. Use it to update the record's OrderIndex on the server.

Backend API
@(Html.DevExtreme().DataGrid<DevExtreme.MVC.Demos.Models.RowReorderingTask>() .ID("gridContainer") .DataSource(d => d.WebApi() .RouteName("DataGridRowReordering") .LoadAction("Tasks") .UpdateAction("UpdateTask") .Key("ID")) .ShowBorders(true) .Height(440) .Sorting(sorting => sorting.Mode(GridSortingMode.None)) .Scrolling(scrolling => scrolling.Mode(GridScrollingMode.Virtual)) .RowDragging(rd => rd .AllowReordering(true) .DropFeedbackMode(DropFeedbackMode.Push) .OnReorder("onReorder") ) .Columns(columns => { columns.AddFor(m => m.ID) .Width(55); columns.AddFor(m => m.Owner) .Width(150) .Lookup(lookup => lookup .DataSource(d => d.WebApi().RouteName("DataGridRowReordering").LoadAction("Employees").Key("ID")) .ValueExpr("ID") .DisplayExpr("FullName") ); columns.AddFor(m => m.AssignedEmployee) .Width(150) .Caption("Assignee") .Lookup(lookup => lookup .DataSource(d => d.WebApi().RouteName("DataGridRowReordering").LoadAction("Employees").Key("ID")) .ValueExpr("ID") .DisplayExpr("FullName") ); columns.AddFor(m => m.Subject); }) ) <script> function onReorder(e) { var dataGrid = e.component, store = dataGrid.getDataSource().store(), visibleRows = dataGrid.getVisibleRows(), newOrderIndex = visibleRows[e.toIndex].data.OrderIndex, d = $.Deferred(); store.update(e.itemData.ID, { OrderIndex: newOrderIndex }).then(function() { dataGrid.refresh().then(d.resolve, d.reject); }, d.reject); e.promise = d.promise(); } </script>
using DevExtreme.MVC.Demos.Models; using DevExtreme.MVC.Demos.Models.DataGrid; using DevExtreme.MVC.Demos.Models.SampleData; using System; using System.Linq; using System.Web.Mvc; namespace DevExtreme.MVC.Demos.Controllers { public class DataGridController : Controller { public ActionResult RemoteReordering() { return View(); } } }
using DevExtreme.AspNet.Data; using DevExtreme.AspNet.Mvc; using Newtonsoft.Json; using System; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Formatting; using System.Web.Http; using DevExtreme.MVC.Demos.Models.DataGrid; using DevExtreme.MVC.Demos.Models.SampleData; namespace DevExtreme.MVC.Demos.Controllers { [Route("api/RowReordering/{action}", Name = "DataGridRowReordering")] public class DataGridRowReorderingController : ApiController { InMemoryRowReorderingTasksDataContext _context = new InMemoryRowReorderingTasksDataContext(); [HttpGet] public HttpResponseMessage Tasks(DataSourceLoadOptions loadOptions) { return Request.CreateResponse(DataSourceLoader.Load(_context.Tasks.OrderBy(t => t.OrderIndex), loadOptions)); } [HttpPut] public HttpResponseMessage UpdateTask(FormDataCollection form) { var key = Convert.ToInt32(form.Get("key")); var values = form.Get("values"); var task = _context.Tasks.First(o => o.ID == key); var oldOrderIndex = task.OrderIndex; JsonConvert.PopulateObject(values, task); var newOrderIndex = task.OrderIndex; Validate(task); if(oldOrderIndex != newOrderIndex) { task.OrderIndex = oldOrderIndex; var sortedTasks = _context.Tasks.OrderBy(t => t.OrderIndex).ToList(); if(oldOrderIndex < newOrderIndex) { for(var i = oldOrderIndex + 1; i <= newOrderIndex; i++) { sortedTasks[i].OrderIndex--; }; } else { for(var i = newOrderIndex; i < oldOrderIndex; i++) { sortedTasks[i].OrderIndex++; }; } task.OrderIndex = newOrderIndex; } if(!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState.GetFullErrorMessage()); _context.SaveChanges(); return Request.CreateResponse(HttpStatusCode.OK, task); } // additional actions [HttpGet] public HttpResponseMessage Employees(DataSourceLoadOptions loadOptions) { return Request.CreateResponse(DataSourceLoader.Load(SampleData.CustomEditorsEmployees, loadOptions)); } } }
using System; using System.Collections.Generic; namespace DevExtreme.MVC.Demos.Models.DataGrid { public class InMemoryRowReorderingTasksDataContext : InMemoryDataContext<RowReorderingTask> { public ICollection<RowReorderingTask> Tasks => ItemsInternal; protected override IEnumerable<RowReorderingTask> Source => SampleData.SampleData.RowReorderingTasks; protected override int GetKey(RowReorderingTask item) => item.ID; protected override void SetKey(RowReorderingTask item, int key) => item.ID = key; } }
using System.ComponentModel.DataAnnotations; namespace DevExtreme.MVC.Demos.Models { public class RowReorderingTask { public int ID { set; get; } [Required] public string Subject { set; get; } [Required] public int Status { set; get; } [Required] public int Owner { set; get; } [Required] public int AssignedEmployee { get; set; } public int OrderIndex { get; set; } public int Priority { get; set; } } }
using System; using System.Collections.Generic; namespace DevExtreme.MVC.Demos.Models.SampleData { public partial class SampleData { public static readonly IEnumerable<RowReorderingTask> RowReorderingTasks = new[] { new RowReorderingTask { ID = 1, Subject = "Prepare 2013 Financial", Status = 5, Owner = 1, AssignedEmployee = 7, OrderIndex = 0, Priority = 3 }, new RowReorderingTask { ID = 2, Subject = "Prepare 2013 Marketing Plan", Status = 5, Owner = 1, AssignedEmployee = 4, OrderIndex = 1, Priority = 4 }, new RowReorderingTask { ID = 3, Subject = "Update Personnel Files", Status = 5, Owner = 1, AssignedEmployee = 2, OrderIndex = 2, Priority = 1 }, new RowReorderingTask { ID = 4, Subject = "Review Health Insurance Options Under the Affordable Care Act", Status = 1, Owner = 1, AssignedEmployee = 2, OrderIndex = 3, Priority = 4 }, new RowReorderingTask { ID = 5, Subject = "Choose between PPO and HMO Health Plan", Status = 4, Owner = 2, AssignedEmployee = 1, OrderIndex = 4, Priority = 3 }, new RowReorderingTask { ID = 6, Subject = "Google AdWords Strategy", Status = 1, Owner = 4, AssignedEmployee = 1, OrderIndex = 5, Priority = 2 }, new RowReorderingTask { ID = 7, Subject = "New Brochures", Status = 1, Owner = 4, AssignedEmployee = 1, OrderIndex = 6, Priority = 1 }, new RowReorderingTask { ID = 8, Subject = "2013 Brochure Designs", Status = 1, Owner = 1, AssignedEmployee = 28, OrderIndex = 7, Priority = 1 }, new RowReorderingTask { ID = 9, Subject = "Brochure Design Review", Status = 1, Owner = 28, AssignedEmployee = 29, OrderIndex = 8, Priority = 1 }, new RowReorderingTask { ID = 10, Subject = "Website Re-Design Plan", Status = 5, Owner = 28, AssignedEmployee = 29, OrderIndex = 9, Priority = 2 }, new RowReorderingTask { ID = 11, Subject = "Rollout of New Website and Marketing Brochures", Status = 5, Owner = 1, AssignedEmployee = 4, OrderIndex = 10, Priority = 2 }, new RowReorderingTask { ID = 12, Subject = "Update Sales Strategy Documents", Status = 5, Owner = 4, AssignedEmployee = 8, OrderIndex = 11, Priority = 2 }, new RowReorderingTask { ID = 13, Subject = "Create 2012 Sales Report", Status = 5, Owner = 8, AssignedEmployee = 41, OrderIndex = 12, Priority = 4 }, new RowReorderingTask { ID = 14, Subject = "Direct vs Online Sales Comparison Report", Status = 5, Owner = 41, AssignedEmployee = 42, OrderIndex = 13, Priority = 3 }, new RowReorderingTask { ID = 15, Subject = "Review 2012 Sales Report and Approve 2013 Plans", Status = 5, Owner = 41, AssignedEmployee = 4, OrderIndex = 14, Priority = 3 }, new RowReorderingTask { ID = 16, Subject = "Deliver R&D Plans for 2013", Status = 2, Owner = 1, AssignedEmployee = 3, OrderIndex = 15, Priority = 2 }, new RowReorderingTask { ID = 17, Subject = "Create 2013 R&D Plans", Status = 5, Owner = 3, AssignedEmployee = 32, OrderIndex = 16, Priority = 0 }, new RowReorderingTask { ID = 18, Subject = "2013 QA Strategy Report", Status = 5, Owner = 32, AssignedEmployee = 33, OrderIndex = 17, Priority = 0 }, new RowReorderingTask { ID = 19, Subject = "2013 Training Events", Status = 5, Owner = 33, AssignedEmployee = 31, OrderIndex = 18, Priority = 0 }, new RowReorderingTask { ID = 20, Subject = "Approve Hiring of John Jeffers", Status = 5, Owner = 31, AssignedEmployee = 5, OrderIndex = 19, Priority = 0 }, new RowReorderingTask { ID = 21, Subject = "Non-Compete Agreements", Status = 5, Owner = 5, AssignedEmployee = 2, OrderIndex = 20, Priority = 0 }, new RowReorderingTask { ID = 22, Subject = "Update NDA Agreement", Status = 5, Owner = 2, AssignedEmployee = 1, OrderIndex = 21, Priority = 0 }, new RowReorderingTask { ID = 23, Subject = "Update Employee Files with New NDA", Status = 1, Owner = 2, AssignedEmployee = 5, OrderIndex = 22, Priority = 3 }, new RowReorderingTask { ID = 24, Subject = "Sign Updated NDA", Status = 5, Owner = 5, AssignedEmployee = 6, OrderIndex = 23, Priority = 0 }, new RowReorderingTask { ID = 25, Subject = "Sign Updated NDA", Status = 5, Owner = 5, AssignedEmployee = 7, OrderIndex = 24, Priority = 0 }, new RowReorderingTask { ID = 26, Subject = "Sign Updated NDA", Status = 1, Owner = 5, AssignedEmployee = 8, OrderIndex = 25, Priority = 1 }, new RowReorderingTask { ID = 27, Subject = "Sign Updated NDA", Status = 4, Owner = 5, AssignedEmployee = 9, OrderIndex = 26, Priority = 0 }, new RowReorderingTask { ID = 28, Subject = "Submit Questions Regarding New NDA", Status = 1, Owner = 9, AssignedEmployee = 17, OrderIndex = 27, Priority = 1 }, new RowReorderingTask { ID = 29, Subject = "Submit Questions Regarding New NDA", Status = 1, Owner = 9, AssignedEmployee = 18, OrderIndex = 28, Priority = 1 }, new RowReorderingTask { ID = 30, Subject = "Submit Questions Regarding New NDA", Status = 4, Owner = 9, AssignedEmployee = 19, OrderIndex = 29, Priority = 0 }, new RowReorderingTask { ID = 31, Subject = "Submit Signed NDA", Status = 5, Owner = 10, AssignedEmployee = 14, OrderIndex = 30, Priority = 0 }, new RowReorderingTask { ID = 32, Subject = "Submit Signed NDA", Status = 5, Owner = 10, AssignedEmployee = 13, OrderIndex = 31, Priority = 0 }, new RowReorderingTask { ID = 33, Subject = "Submit Signed NDA", Status = 5, Owner = 10, AssignedEmployee = 15, OrderIndex = 32, Priority = 0 }, new RowReorderingTask { ID = 34, Subject = "Submit Signed NDA", Status = 5, Owner = 10, AssignedEmployee = 16, OrderIndex = 33, Priority = 0 }, new RowReorderingTask { ID = 35, Subject = "Update Revenue Projections", Status = 5, Owner = 1, AssignedEmployee = 7, OrderIndex = 34, Priority = 0 }, new RowReorderingTask { ID = 36, Subject = "Review Revenue Projections", Status = 5, Owner = 7, AssignedEmployee = 8, OrderIndex = 35, Priority = 0 }, new RowReorderingTask { ID = 37, Subject = "Comment on Revenue Projections", Status = 5, Owner = 7, AssignedEmployee = 41, OrderIndex = 36, Priority = 0 }, new RowReorderingTask { ID = 38, Subject = "Comment on Revenue Projections", Status = 5, Owner = 7, AssignedEmployee = 42, OrderIndex = 37, Priority = 0 }, new RowReorderingTask { ID = 39, Subject = "Comment on Revenue Projections", Status = 1, Owner = 7, AssignedEmployee = 45, OrderIndex = 38, Priority = 2 }, new RowReorderingTask { ID = 40, Subject = "Provide New Health Insurance Docs", Status = 5, Owner = 11, AssignedEmployee = 5, OrderIndex = 39, Priority = 0 }, new RowReorderingTask { ID = 41, Subject = "Review Changes to Health Insurance Coverage", Status = 5, Owner = 11, AssignedEmployee = 10, OrderIndex = 40, Priority = 0 }, new RowReorderingTask { ID = 42, Subject = "Scan Health Insurance Forms", Status = 5, Owner = 10, AssignedEmployee = 14, OrderIndex = 41, Priority = 0 }, new RowReorderingTask { ID = 43, Subject = "Sign Health Insurance Forms", Status = 5, Owner = 14, AssignedEmployee = 15, OrderIndex = 42, Priority = 0 }, new RowReorderingTask { ID = 44, Subject = "Sign Health Insurance Forms", Status = 5, Owner = 14, AssignedEmployee = 13, OrderIndex = 43, Priority = 0 }, new RowReorderingTask { ID = 45, Subject = "Sign Health Insurance Forms", Status = 3, Owner = 14, AssignedEmployee = 16, OrderIndex = 44, Priority = 0 }, new RowReorderingTask { ID = 46, Subject = "Follow up with West Coast Stores", Status = 1, Owner = 9, AssignedEmployee = 18, OrderIndex = 45, Priority = 3 }, new RowReorderingTask { ID = 47, Subject = "Follow up with East Coast Stores", Status = 1, Owner = 9, AssignedEmployee = 17, OrderIndex = 46, Priority = 3 }, new RowReorderingTask { ID = 48, Subject = "Send Email to Customers about Recall", Status = 5, Owner = 9, AssignedEmployee = 19, OrderIndex = 47, Priority = 0 }, new RowReorderingTask { ID = 49, Subject = "Submit Refund Report for 2013 Recall", Status = 5, Owner = 7, AssignedEmployee = 9, OrderIndex = 48, Priority = 0 }, new RowReorderingTask { ID = 50, Subject = "Give Final Approval for Refunds", Status = 5, Owner = 7, AssignedEmployee = 2, OrderIndex = 49, Priority = 0 }, new RowReorderingTask { ID = 51, Subject = "Prepare Product Recall Report", Status = 5, Owner = 3, AssignedEmployee = 32, OrderIndex = 50, Priority = 0 }, new RowReorderingTask { ID = 52, Subject = "Review Product Recall Report by Engineering Team", Status = 5, Owner = 3, AssignedEmployee = 1, OrderIndex = 51, Priority = 0 }, new RowReorderingTask { ID = 53, Subject = "Create Training Course for New TVs", Status = 5, Owner = 32, AssignedEmployee = 31, OrderIndex = 52, Priority = 0 }, new RowReorderingTask { ID = 54, Subject = "Review Training Course for any Omissions", Status = 5, Owner = 31, AssignedEmployee = 33, OrderIndex = 53, Priority = 0 }, new RowReorderingTask { ID = 55, Subject = "Review Overtime Report", Status = 5, Owner = 5, AssignedEmployee = 6, OrderIndex = 54, Priority = 0 }, new RowReorderingTask { ID = 56, Subject = "Submit Overtime Request Forms", Status = 5, Owner = 6, AssignedEmployee = 21, OrderIndex = 55, Priority = 0 }, new RowReorderingTask { ID = 57, Subject = "Submit Overtime Request Forms", Status = 5, Owner = 6, AssignedEmployee = 22, OrderIndex = 56, Priority = 0 }, new RowReorderingTask { ID = 58, Subject = "Submit Overtime Request Forms", Status = 5, Owner = 6, AssignedEmployee = 23, OrderIndex = 57, Priority = 0 }, new RowReorderingTask { ID = 59, Subject = "Overtime Approval Guidelines", Status = 5, Owner = 6, AssignedEmployee = 2, OrderIndex = 58, Priority = 0 }, new RowReorderingTask { ID = 60, Subject = "Refund Request Template", Status = 3, Owner = 12, AssignedEmployee = 8, OrderIndex = 59, Priority = 0 }, new RowReorderingTask { ID = 61, Subject = "Recall Rebate Form", Status = 3, Owner = 12, AssignedEmployee = 8, OrderIndex = 60, Priority = 0 }, new RowReorderingTask { ID = 62, Subject = "Create Report on Customer Feedback", Status = 5, Owner = 30, AssignedEmployee = 12, OrderIndex = 61, Priority = 0 }, new RowReorderingTask { ID = 63, Subject = "Review Customer Feedback Report", Status = 5, Owner = 30, AssignedEmployee = 8, OrderIndex = 62, Priority = 0 }, new RowReorderingTask { ID = 64, Subject = "Customer Feedback Report Analysis", Status = 3, Owner = 8, AssignedEmployee = 1, OrderIndex = 63, Priority = 0 }, new RowReorderingTask { ID = 65, Subject = "Prepare Shipping Cost Analysis Report", Status = 5, Owner = 8, AssignedEmployee = 10, OrderIndex = 64, Priority = 0 }, new RowReorderingTask { ID = 66, Subject = "Provide Feedback on Shippers", Status = 5, Owner = 10, AssignedEmployee = 13, OrderIndex = 65, Priority = 0 }, new RowReorderingTask { ID = 67, Subject = "Provide Feedback on Shippers", Status = 5, Owner = 10, AssignedEmployee = 15, OrderIndex = 66, Priority = 0 }, new RowReorderingTask { ID = 68, Subject = "Provide Feedback on Shippers", Status = 5, Owner = 10, AssignedEmployee = 16, OrderIndex = 67, Priority = 0 }, new RowReorderingTask { ID = 69, Subject = "Select Preferred Shipper", Status = 5, Owner = 10, AssignedEmployee = 2, OrderIndex = 68, Priority = 0 }, new RowReorderingTask { ID = 70, Subject = "Complete Shipper Selection Form", Status = 3, Owner = 2, AssignedEmployee = 1, OrderIndex = 69, Priority = 0 }, new RowReorderingTask { ID = 71, Subject = "Upgrade Server Hardware", Status = 5, Owner = 22, AssignedEmployee = 6, OrderIndex = 70, Priority = 0 }, new RowReorderingTask { ID = 72, Subject = "Upgrade Personal Computers", Status = 4, Owner = 21, AssignedEmployee = 6, OrderIndex = 71, Priority = 0 }, new RowReorderingTask { ID = 73, Subject = "Approve Personal Computer Upgrade Plan", Status = 5, Owner = 6, AssignedEmployee = 2, OrderIndex = 72, Priority = 0 }, new RowReorderingTask { ID = 74, Subject = "Decide on Mobile Devices to Use in the Field", Status = 5, Owner = 6, AssignedEmployee = 3, OrderIndex = 73, Priority = 0 }, new RowReorderingTask { ID = 75, Subject = "Upgrade Apps to Windows RT or stay with WinForms", Status = 5, Owner = 24, AssignedEmployee = 6, OrderIndex = 74, Priority = 0 }, new RowReorderingTask { ID = 76, Subject = "Estimate Time Required to Touch-Enable Apps", Status = 5, Owner = 24, AssignedEmployee = 25, OrderIndex = 75, Priority = 0 }, new RowReorderingTask { ID = 77, Subject = "Report on Tranistion to Touch-Based Apps", Status = 5, Owner = 6, AssignedEmployee = 23, OrderIndex = 76, Priority = 0 }, new RowReorderingTask { ID = 78, Subject = "Try New Touch-Enabled WinForms Apps", Status = 5, Owner = 6, AssignedEmployee = 3, OrderIndex = 77, Priority = 0 }, new RowReorderingTask { ID = 79, Subject = "Rollout New Touch-Enabled WinForms Apps", Status = 4, Owner = 6, AssignedEmployee = 24, OrderIndex = 78, Priority = 0 }, new RowReorderingTask { ID = 80, Subject = "Site Up-Time Report", Status = 5, Owner = 3, AssignedEmployee = 6, OrderIndex = 79, Priority = 0 }, new RowReorderingTask { ID = 81, Subject = "Review Site Up-Time Report", Status = 5, Owner = 3, AssignedEmployee = 4, OrderIndex = 80, Priority = 0 }, new RowReorderingTask { ID = 82, Subject = "Review Online Sales Report", Status = 5, Owner = 4, AssignedEmployee = 1, OrderIndex = 81, Priority = 0 }, new RowReorderingTask { ID = 83, Subject = "Determine New Online Marketing Strategy", Status = 5, Owner = 4, AssignedEmployee = 8, OrderIndex = 82, Priority = 0 }, new RowReorderingTask { ID = 84, Subject = "New Online Marketing Strategy", Status = 5, Owner = 8, AssignedEmployee = 42, OrderIndex = 83, Priority = 0 }, new RowReorderingTask { ID = 85, Subject = "Approve New Online Marketing Strategy", Status = 5, Owner = 8, AssignedEmployee = 4, OrderIndex = 84, Priority = 0 }, new RowReorderingTask { ID = 86, Subject = "Submit New Website Design", Status = 5, Owner = 8, AssignedEmployee = 28, OrderIndex = 85, Priority = 0 }, new RowReorderingTask { ID = 87, Subject = "Create Icons for Website", Status = 5, Owner = 28, AssignedEmployee = 29, OrderIndex = 86, Priority = 0 }, new RowReorderingTask { ID = 88, Subject = "Review PSDs for New Website", Status = 5, Owner = 28, AssignedEmployee = 6, OrderIndex = 87, Priority = 0 }, new RowReorderingTask { ID = 89, Subject = "Create New Shopping Cart", Status = 5, Owner = 6, AssignedEmployee = 24, OrderIndex = 88, Priority = 0 }, new RowReorderingTask { ID = 90, Subject = "Create New Product Pages", Status = 5, Owner = 6, AssignedEmployee = 25, OrderIndex = 89, Priority = 0 } }; } }

In this demo, we use the onReorder function's toIndex parameter to obtain the position at which a user dropped the row. The position is then used to get the new order index. The store's update method sends this index to the server where the records are sorted and returned to the client. Server-side implementation is available under the DataGridRowReorderingController.cs tab.