En estos momentos estoy trabajando en un proyecto utilizando extensiones MVC de DevExpress, y quería añadir la funcionalidad de arrastrar y soltar (drag & drop) dentro de un FormLayout Control en la vista de un listado. Es decir, el usuario podrá agregar/quitar, es decir, arrastrar y soltar para organizar elementos <li>, para después, obtener el orden final actualizado. Dado que la funcionalidad no está integrada en el control DevExpress, decidí modificar la librería open source que estaba usando, jQuery-UI.
En este artículo utilizaré DevExpress, Bootstrap y la librería jQuery-ui.
Descripción de la función
El usuario puede añadir nuevos elementos a la lista mediante el cuadro de texto y el botón "Add", reorganizar los elementos enumerados arrastrando y soltando, quitar un elemento haciendo clic en el botón (x) a la derecha del mismo y durante todos estos eventos, se actualizará la base de datos.
Se deshabilitará el botón Add si el cuadro de texto Name está vacío. Esto evita que se agreguen elementos vacíos a la lista.
Echa un vistazo:
El código
Para ver el código completo de index.cshtml pincha en este enlace.
Lo primero que tenemos que hacer es crear el FormLayout mediante código Razor. Después añadimos la funcionalidad sortable de jQuery-ui en el elemento <ul>
1. Creamos el control FormLayout en el index.cshtml
// FormLayout control from DevExpress @Html.DevExpress().FormLayout(formLayoutSettings => { formLayoutSettings.Name = "mainForm"; formLayoutSettings.Width = System.Web.UI.WebControls.Unit.Percentage(50); // set the width to 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;">"); // text box for list item name Html.DevExpress().TextBox(tbs => { tbs.Name = "listItemTextBox"; tbs.Properties.Caption = "Name"; tbs.Properties.ClientSideEvents.KeyUp = "OnlistItemTextBoxKeyUp"; // checks when to enable/disable Add button }).GetHtml(); ViewContext.Writer.Write("</td><td>"); Html.DevExpress().Button(bs => { bs.Name = "addButton"; bs.Text = "Add"; bs.ClientSideEvents.Click = "OnAddButtonClick"; bs.ClientEnabled = false; // by default or initial load // keeps the button disabled }).GetHtml(); ViewContext.Writer.Write("</td></tr></table>"); ViewContext.Writer.Write("<br />"); // List items can be re-arranged, deleted from this <ul> 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. Después, añadimos CSS para el diseño de las listas
<style> #ulContent { list-style-type: none; /*removes the default bullet point*/ margin: 0; padding: 0; } #ulContent li { /* makes the room for adding draggable icon on the left */ margin: 0 3px 3px 3px; display: list-item; padding-left: 1.5em; } #ulContent li span { /* aligns the span properly */ display: inline-block; margin-left: -1.3em; } </style>
3. Ahora, añadimos el Javascript que gestiona el evento drag & drop, modificamos la vista después de cada inserción/eliminación/cambio de orden de la lista de elementos.
$(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); }
Fuente: asutreja