Ejemplo más complejo de Drag & Drop con jQueryUI

  • Por
Veamos casos un poco más elaborados de utilidades Drag & Drop en páginas web, por medio de jQueryUI.

En el Manual de jQueryUI hemos tratado ya bastantes cosas tanto de los elementos Draggable como de los elementos Droppable. Creo que para afianzar estos conocimientos nos vendría bien trabajar con algún ejemplo un poquito más elaborado.

A este ejemplo que vamos a realizar lo he llamado Azules y Rojos y consiste en diversas capas de colores azules y rojos y dos contenedores que aceptan soltar sobre ellos elementos de un tipo concreto. El contenedor rojo acepta que soltemos sobre él cajitas rojas y el azul solo acepta cajitas azules, llevando la cuenta de todas las cajitas que fueron depositadas en ellos.

Es bien simple, pero para darnos cuenta de lo que vamos a realizar os recomiendo parar un instante para ver el ejemplo en marcha.

Nuestro HTML

Comencemos por analizar el código HTML que tenemos en nuestro ejemplo.

<div class="azul arrastrable" style="top: 140px; left: 150px;"></div> 
<div class="rojo arrastrable" style="top: 98px; left: 100px;"></div> 
<div class="rojo arrastrable" style="top: 120px; left: 180px;"></div> 
<div class="azul arrastrable" style="top: 120px; left: 90px;"></div> 

<div id="sueltarojo" class="suelta"> 
   Suelta aquí elementos rojos 
</div> 
<div id="sueltaazul" class="suelta"> 
   Suelta aquí elementos azules 
</div>

Como puedes ver tenemos varios elementos DIV con la clase "arrastrable", que son los elementos que vamos a poder arrastrar por la página. A estos elementos voy a llamartes cajitas. Adicionalmente, estas cajitas tienen la clase "azul" unas y otras la clase "rojo". Esas clases nos van a servir, no solo para decorarlos con CSS, sino para saber cuáles de esas cajitas se van a aceptar en los contenedores correspondientes. Bien sencillo.

Además tenemos un poco más abajo en el código HTML un par de contendores, también elementos DIV, que son los lugares donde voy a soltar las cajitas y solo aceptarán las del color que le corresponda.

Javascript para crear los elementos "draggables" (las cajitas)

Ahora que tenemos clara la noción de los elementos HTML que forman parte de nuestro ejemplo, podemos analizar el código Javascript que servirá para crear las funcionalidades dinámicas. Comenzamos viendo cómo hacer que las cajitas se puedan arrastrar.

$(".arrastrable").draggable();

Con esta sencilla llamada al método draggable() podemos arrastrar las cajitas, a las que les había puesto la clase "arrastrable". La verdad es que esta parte es bien simple y como veremos en breve, la complejidad se nos va a concentrar en los elementos "droppable".

No obstante, aquí vemos un código adicional que he creado simplemente para saber si un elemento fue o no soltado anteriormente sobre un contenedor que lo aceptase.

$(".arrastrable").data("soltado", false);

Ese método data(), como debemos saber, me sirve para almacenar cualquier tipo de dato dentro de un objeto jQuery. Insisto, no es que necesite hacer esto para convertir a las cajitas en arrastrables, es solo que la operativa de mi ejemplo va a necesitar saber si una cajita fue ya depositada, o no, en un contenedor.

Definición del comportamiento de soltar ("droppable" sobre los contenedores)

Ahora vamos a ver el Javascript para definir el comportamiento de soltar cajitas sobre los contenedores. Pero antes un detalle. Como había dicho, pretendo llevar la cuenta de las cajitas que fueron soltadas en cada contenedor. Para ello voy a crear con el método data() una variable para hacer de contador.

$(".suelta").data("numsoltar", 0);

Lo hago sobre los elementos de la clase "suelta", que es una clase que tienen tanto el contenedor rojo como el azul.

Ahora, sobre esta misma clase "suelta" voy a definir con jQueryUI que sean elementos "droppable", que es donde está la mayor complejidad de este ejercicio.

$(".suelta").droppable({ 
   drop: function( event, ui ) { 
      if (!ui.draggable.data("soltado")){ 
         ui.draggable.data("soltado", true); 
         var elem = $(this); 
         elem.data("numsoltar", elem.data("numsoltar") + 1) 
         elem.html("Llevo " + elem.data("numsoltar") + " elementos soltados"); 
      } 
   }, 
   out: function( event, ui ) { 
      if (ui.draggable.data("soltado")){ 
         ui.draggable.data("soltado", false); 
         var elem = $(this); 
         elem.data("numsoltar", elem.data("numsoltar") - 1); 
         elem.html("Llevo " + elem.data("numsoltar") + " elementos soltados"); 
      } 
   } 
});

Se trata de una llamada al método droppable(), pasando dos funciones para gestionar tanto el evento "drop" (que se ejecuta al soltar un "draggable"), como el evento "out" (que se ejecuta al sacar un "draggable"). Lo interesante está justamente en estos eventos.

El evento drop, que se activa al soltar una cajita, realiza una comprobación sobre la cajita que se está soltando. Para acceder al objeto jQuery de esa cajita utilizamos el parámetro "ui" que recibe la función del evento y su propiedad draggable. Es decir, ui.draggable es una referencia al objeto jQuery que estamos soltando encima del contenedor. La comprobación simplemente accede a la variable que habíamos almacenado en la cajita con el método data(), para saber si esta cajita se había soltado previamente o no.

Si no se había soltado, por medio del evento drop realizo todas las operaciones que deseo, que son:

  • Marcar a la cajita como que ha sido soltada, almacenando otro valor con data().
  • Acceder al elemento contenedor y guardar una referencia en la variable elem.
  • Incrementar en 1 el número de cajitas soltadas sobre ese elemento, por medio del contador que habíamos creado con data().
  • Cambiar el contenido del contenedor para decir que llevo tantos elementos soltados como los indicados por nuestro contador.
Por su parte, el evento out, que se activa al sacar una cajita que previamente fue soltada, hace un poco lo mismo pero en sentido contrario. Es decir, si la caja estaba soltada previamente y ahora la estamos sacando del contenedor, pues la marco como no soltada, resto 1 al contador y actualizo el texto del contenedor.

Hasta aquí todo bien ¿no? Pero ahora os podéis preguntar ¿no habíamos quedado en que el contenedor azul solo tenía que aceptar las cajitas azules y el rojo solamente las rojas? Efectivamente, pero por darle variedad a este ejemplo, he dejado esas dos modificaciones fuera de la creación de los "droppables".

//soltar solo elementos rojos 
$("#sueltarojo").droppable("option", "accept", ".rojo"); 
//soltar solo elementos azules 
$("#sueltaazul").droppable("option", "accept", ".azul");

Con este código conseguimos modificar propiedades de los elementos droppable, para que solo acepten los elementos de una clase. En realidad se hace simplemente marcando con el atrubito "accept" el valor del selector que identifique los elementos que sí deseamos aceptar. En este caso los elementos de la clase "rojo" se aceptan en el contenedor con id "sueltarojo" y los elementos de la clase "azul" se aceptan en el contenedor con id "sueltazul".

Insisto en que ese comportamiento lo podía haber definido al invocar al método droppable(), en el momento de creación del comportamiento de soltar. Sin embargo, también por medio del método "option" puedo hacer esta configuración después de haber creado el componente droppable.

Conclusión

La funcionalidad básica de este ejercicio, al menos la que tiene que ver con el Drag & Drop, ya la hemos visto toda. En el ejemplo en marcha podrás ver que también hay unos enlaces para poder hacer más cajitas, azules o rojas, en tiempo de ejecución de la página. Esas cajitas creadas sobre la marcha se posicionan en un lugar aleatorio de la página y las podemos arrastrar también sobre los elementos droppable.

El código para crear ese comportamiento en los es el siguiente:

//enlaces para crear nuevos elementos rojos y azules 
$(".creaelemento").click(function(e){ 
   e.preventDefault(); 
   var posx = aleatorio(10, 500); 
   var posy = aleatorio(80, 200); 
   var nuevoElemento = $('<div class="' + $(this).attr("href") + ' arrastrable" style="top: ' + posy + 'px; left: ' + posx + 'px;"></div>'); 
   nuevoElemento.draggable(); 
   $(document.body).append(nuevoElemento); 
})

No voy a explicar este código de momento, pues no tiene nada en especial que no hayamos visto o en el Manual de jQuery o en el Manual de jQueryUI.

Espero que la parte del comportamiento de arrastrar y soltar, que era la que nos interesaba, se haya podido entender perfectamente con este ejemplo.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

Sam Ciar

31/7/2014
Consulta, evitar que se pueda correr y salir de la pagina cuando se arrastra
Buenas noches, he notado que en el ejercicio al momento de usar el drag, cuando estoy arrasttrando el objeto y tiro el cursos con el objeto al borde de la pagina, puedo salirme de ella, corriendo toda la pagina y generando los scrolls hacia cualquier lado......



como puedo evitar esto?

ivan

24/8/2015
Codigo
Hola, muy buen articulo, lo que pasa es que el codigo esta inacabado, podria tener el codigo del ejemplo?

un saludo

Carlos Quilligana

24/5/2017
Borrar
Como puedo borrar solo el cuadro nuevo que acabo de crear ???

Guillermo

08/6/2017
Muy bueno
Muchas gracias por el código, es muy sencillo y facil de usar

martha

11/4/2018
axilio
como guardar posicion de un drag y drop en javascript