Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Drag and Drop with DevExpress MVC Controls

5.00/5 (1 vote)
11 Jul 2017CPOL1 min read 11.2K   1  
Dragging List items within DevExpress MVC FormLayout control to re-arrange/order by end users

This article appears in the Third Party Products and Tools section. Articles in this section are for the members only and must not be used to promote or advertise products in any way, shape or form. Please report any spam or advertising.

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:

Image 1

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:
    Razor
    @* 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:
    JavaScript
    @* 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.
    JavaScript
    <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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)