August 14, 2018

How to Make your Own Drag and Drop Idea Board

As mobile and tablet use continues to increase, website users are coming to the websites expecting app-like elements. More and more websites are using the expandable hamburger menu even at large resolutions. Marketing sliders are built to respond to a finger-slide. As developers, we are looking for small ways like this to create a more app-like experience for our users. One way we have done this recently at E-dreamz is the implementation of a drag-and-drop Idea Board for Carolina Fitness Equipment. The Idea Board is essentially a wishlist of products that you can add to by dragging products on any listing page into a tray that is fixed to the side of the window.





We simply use the jQuery UI library to attach a draggable feature to the .product-list-item and a droppable feature to the .idea-board.

Javscript:
<code class="language-javascript">
$( ".product-list-item" ).draggable({
    revert: true, // this means the element won’t remain wherever you drag it
    revertDuration: 150,
    stack: ".prodList > div"
});
$(".idea-board").droppable({
    accept: '.product-list-item',
});
</code>



We’ve made various styling and animation choices to help guide the user through the process.

1. The product item becomes semi-transparent when being dragged.


CSS:
<code class="language-css">
.product-list-item.ui-draggable-dragging { 
    opacity: .35; 
    z-index: 20 !important; 
}
</code>


2. When on top of the tray, the tray expands to displays an empty place with a dotted border. This makes it clear to the user that the tray is ready to accept the product so they can release it. This is accomplished by changing classes in the over() function

Javscript:
<code class="language-javascript">
$(".idea-board").droppable({
    over: function (e) {
        e.preventDefault();
        $(this).addClass("active"); // expands the tray
        $(".wishlistItems").prepend('<div class="item hovering"></div>'); // adds a new, highlighted space at the 
                                         // beginning of the list of items
    }
});
</code>
CSS:
<code class="language-css">
.idea-board.active { 
    width: 580px; }
.idea-board .wishlistItems .item { 
    width: 32%; 
    margin-left: 2%; 
    float: left; 
    margin-bottom: 10px; 
    min-height: 100px; 
    transition: background 150ms linear; }
.idea-board .wishlistItems .item:not(.filled) { 
    background: rgba(255, 255, 255, 0.3); 
    border: 2px dashed #fff; }
.idea-board .wishlistItems .item.hovering { 
    background: rgba(255, 255, 255, 0.8); }
</code>

3. Once the product is dropped in the tray, we have a simple loading spinner to let the user know the item is being processed. In the drop function, we handle the ajax call to add the product to the Idea Board. It’s actually the ajax call that sets up and destroys the loader.


Javscript:
<code class="language-javascript">
$(".idea-board").droppable({
    drop:function(event,ui){
        $(".idea-board").addClass("loading");
        /* Code here extracts the product information, 
           constructs the dataString, and 
           selects the url for the ajax call */

        $.ajax({
            type: "POST",
            url : url,
            data : dataString,
            success : function(data){
              /* Add the product image to the highlighted item
                 and un-highlight it. */
              $(".idea-board .hovering").html('<a href="'+$(ui.draggable).attr("data-url")+'" data-id="'+$(ui.draggable).attr("data-id")+'"><img src="'+$(ui.draggable).attr("data-thumbnail")+'"></a>');  
              $(".idea-board .hovering").removeClass("hovering").addClass("filled");
              $(".idea-board").addClass("added");
              setTimeout(function(){
                $(".idea-board").removeClass("loading").removeClass("added");
                    },1400); 
                assignDraggable(); // explained below
              }
            },
            error: function(data) {
                alert('Error adding to your idea board');
                $(".idea-board .hovering").remove();
                $(".idea-board").removeClass("loading");
            }
        },"json");
    }
});
</code>
CSS:
<code class="language-css">
.idea-board .iloader { 
     display: none; 
     align-items: center; 
     justify-content: center; 
     background: rgba(255, 255, 255, 0.7); 
     position: absolute; 
     top: 0; 
     left: 0; 
     width: 100%; 
     height: 100%; 
     z-index: 2; }
.idea-board .iloader .spinner { 
     width: 100px; 
     height: 100px; 
     border-radius: 50%; 
     border: 6px dashed #29b473; 
     animation-name: spin; 
     animation-duration: 3500ms; 
     animation-iteration-count: infinite; 
     animation-timing-function: linear; }
.idea-board.loading .iloader { 
     display: flex; 
     /* Flex is used to center the spinner within the space */
}
@keyframes spin { from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
</code>


Once the item is successfully added, the loader is replaced with a checkmark and the product image appears at the beginning of the list.


CSS:
<code class="language-css">
.idea-board.added .iloader .spinner { 
     animation: none; 
     border: 0; }
.idea-board.added .iloader .spinner:before { 
     content: "\f05d"; 
     font-family: "FontAwesome"; 
     font-size: 85px; 
     line-height: 100px; 
     color: #29b473; }
</code>


4. To continue with our user-friendly, app-like experience, we setup the Delete from Idea Board functionality to also be drag-drop. When the user grabs one of the items in the Idea Board, the trash icon in the corner is highlighted and expanded, to guide the user to drag it there. We assign the draggable attribute to the idea board items via a function. This function is called whenever new items are added to the Idea Board (see ajax function in #3). We assign our delete icon to be droppable. When the user drops the product here, an ajax function is called which them removes the Idea Board item from the tray. While this is processing, we show the loader again to make it clear to the user what is happening.




Javscript:
<code class="language-javascript">
function assignDraggable(){
    $( ".wishlistItems .item" ).draggable({
        revert: true,
        revertDuration: 150,
        stack: ".wishlistItems .item",
        start:function(){
            $(".delete").addClass("active");
        },
        stop:function(){
            $(".idea-board .delete").removeClass("active");
        }
    });
}
$(".idea-board .delete").droppable({
    over:function(e){
        $(".idea-board .delete").addClass("hover");
    },
    out:function(){
        $(".idea-board .delete").removeClass("hover");
    },
    drop:function(event,ui){
        $(".idea-board").addClass("loading");
        
        /* Code here extracts the product information, 
           constructs the dataString, and 
           selects the url for the ajax call */

        $.ajax({
            type: "POST",
            url : url,
            data : dataString,
            success : function(data){                   
                $(ui.draggable).remove(); //removes the item from the tray
                setTimeout(function(){
                    $(".idea-board").removeClass("loading").removeClass("added");
                },1400);
            }
        },"json");
    }
});
</code>
CSS:
<code class="language-css">
.idea-board .delete { 
     border-radius: 50%; 
     position: absolute; 
     bottom: 8px; 
     left:8px; 
     color: #000; 
     font-size: 25px; 
     width: 80px; 
     text-align: center; 
     line-height: 80px; 
     opacity: .6; }
.idea-board .delete.active { 
     background: rgba(255, 255, 255, 0.6); 
     display: block; 
     font-size: 35px; }
</code>

As you can see, using highlighting and expanding various elements, we guide the user through a feature that is not very common on traditional websites. I believe we will see more and more use of drag-drop elements especially as touch-screen laptops become the norm.
BACK TO BLOG

By: Katelynn Barlowe

Full Stack Developer