65.9K
CodeProject is changing. Read more.
Home

Drag and Drop with DevExpress MVC Controls

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1 vote)

Jul 9, 2017

CPOL

1 min read

viewsIcon

11220

downloadIcon

1

Dragging List items within DevExpress MVC FormLayout control to re-arrange/order by end users

Introduction

Recently, I was working on a project using DevExpress MVC Extensions, and I wanted to add drag and drop functionality within a FormLayout Control for a list view. So, user can add/remove or drag & drop to re-arrange the <li> elements, then get the final order after each updated arrangement. Since the functionality is not already built-into the DevExpress control, I decided to go with the existing open source library I was using, jQuery-UI.

Note: The code in this article uses DevExpress, Bootstrap, and jQuery-ui library.

Feature Overview

The user can add new items to the list using the text box and the "Add" button, rearrange the listed items by dragging & dropping, remove the item by clicking (x) button on the right of the item, and during all these events, the Display List items gets updated.

Note: Add button is disabled if the Name textbox is empty. This prevents empty items being added to the list.

See the image:

Using the Code

Note: For the complete Index.cshtml sample code, see the attached file.

The first step is to create a FormLayout using Razor code. Then add the jQuery-ui's sortable functionality on the <ul> element.

  1. Create the FormLayout control in the Index.cshtml:
    @* FormLayout control from DevExpress *@
    @Html.DevExpress().FormLayout(formLayoutSettings =>
    {
        formLayoutSettings.Name = "mainForm";
        // sets the width to 50%
        formLayoutSettings.Width = System.Web.UI.WebControls.Unit.Percentage(50);
    
        // Display List Items Group
        formLayoutSettings.Items.AddGroupItem(listItemsSettings =>
        {
            listItemsSettings.Caption = "Display List Items";
    
            listItemsSettings.Items.Add(i =>
            {
                i.ShowCaption = DefaultBoolean.False;
                i.SetNestedContent(() =>
                {
                    // every time new item is added/removed or re-ordered, this display <p> will get updated
                    ViewContext.Writer.Write("<p id='listItems'></p>");
                });
            });
        });
    
        // Input Group
        formLayoutSettings.Items.AddGroupItem(inputGroupSettings =>
        {
            inputGroupSettings.Caption = "Input";
    
            inputGroupSettings.Items.Add(i =>
            {
                i.ShowCaption = DefaultBoolean.False;
    
                i.SetNestedContent(() =>
                {
                    // puts some padding for the layout
                    ViewContext.Writer.Write("<table><tr><td style=\"padding-right:5px;\">");
    
                    // Textbox for list item name
                    Html.DevExpress().TextBox(tbs =>
                    {
                        tbs.Name = "listItemTextBox";
                        tbs.Properties.Caption = "Name";
                        // clientside event checks when to enable/disable the Add button
                        tbs.Properties.ClientSideEvents.KeyUp = "OnlistItemTextBoxKeyUp";
                    }).GetHtml();
    
                    ViewContext.Writer.Write("</td><td>");
    
                    // Add button
                    Html.DevExpress().Button(bs =>
                    {
                        bs.Name = "addButton";
                        bs.Text = "Add";
                        bs.ClientSideEvents.Click = "OnAddButtonClick";
                        // by default or initial load keeps the button disabled
                        bs.ClientEnabled = false;
                    }).GetHtml();
    
                    ViewContext.Writer.Write("</td></tr></table>");
                    ViewContext.Writer.Write("<br />");
                    // List items are put into this unordered list element
                    ViewContext.Writer.Write("<h5><strong>List Items:</strong></h5><div style='width:100%; height:150px; overflow:auto; border:solid thin;'><ul id='ulContent'></ul></div>");
                });
            });
        });
    
    }).GetHtml()
    
  2. Next, add some CSS for the List items layout:
    @* Custom style used for sortable <ul> element's content for draggable <li> elements, and remove button *@
    <style>
        #ulContent {
            /*removes the default bullet point*/
            list-style-type: none;
            margin: 0;
            padding: 0;
        }
    
        /* makes the room for adding draggable icon on the left */
        #ulContent li {
            margin: 0 3px 3px 3px;
            display: list-item;
            padding-left: 1.5em;
        }
    
        /* aligns the span properly */
        #ulContent li span {
            display: inline-block;
            margin-left: -1.3em;
        }
    </style>
  3. Now, add the JavaScript to handle the drag & drop event, update the display view after each remove/add/re-arrangement of the list items.
    <script>
        $(document).ready(function () {
            $(function () {
                // makes the <li> elements to be draggable by using jQuery-ui library
                $("#ulContent").sortable();
                // disable selection
                $("#ulContent").disableSelection();
            });
    
            // attach update event for the unordered list element
            // (this event is triggered when new list item is added, removed or re-arranged by dragging)
            $("#ulContent").sortable({
                update: function (event, ui) {
                    // Update the display label
                    UpdateDisplayLabel();
                }
            });
        });
    
        // when list element element's remove (x) button is clicked, remove the element from the list and updates the display label
        function OnRemoveListItem(buttonElement) {
            //  get parent element of the button and remove it
            $(buttonElement).parent().remove();
    
            // Update the display label
            UpdateDisplayLabel();
        }
    
        // checks whether to enable/disable the Add button
        function OnlistItemTextBoxKeyUp(s, e) {
            if (s.GetText().trim() == "") {
                 // disable the Add button if the text box is empty or contains only spaces
                addButton.SetEnabled(false);
            } else {
                addButton.SetEnabled(true);
            }
        }
    
        // When Add button is clicked, adds the new list item to the un ordered list element
        function OnAddButtonClick(s, e) {
            $('#ulContent').append("<li class='ui-state-default'><span class='ui-icon ui-icon-arrowthick-2-n-s' style='align-content:center'></span>" + listItemTextBox.GetText() + "<span role='button' onclick='OnRemoveListItem($(this))' class='ui-icon ui-icon-circlesmall-close' style='float:right'></span></li>");
    
            // resets the textbox to empty string
            listItemTextBox.SetText("");
            // disable the Add button
            addButton.SetEnabled(false);
    
            // Update the display label
            UpdateDisplayLabel();
        }
    
        // updates the display label
        function UpdateDisplayLabel() {
            var listItemsString = "";
            // loop through all list item inside the ulContent
            $("#ulContent li").each(function (idx, li) {
                listItemsString = listItemsString + " <" + $(li).text() + ">";
            });
    
            // set the new label for Display List Items
            $("#listItems").text(" " + listItemsString);
        }
    </script>
    

History

  • 9th July, 2017 - First version

References