Experiment – Mobile Move

Recently I was asked to take a look at some of the complications surrounding drag-and-drop behaviour on mobile. A client had some grouped lists that utilised dragging on desktop to re-order.

Although various polyfill solutions enabled the behaviour to be mimicked on mobile (touch punch was the best from the research I conducted), this particular example often contained sizeable lists, and due to the size of the content within each item, only 2-3 items were ever present within the viewport at any one time. This raised an obvious question; does this really work for people on mobile phones?

After deciding that this behaviour needed to be re-worked on small screens, I went about working on alternatives. It seemed as though the current problem rested in two key areas:

1) It was difficult and annoying to hold down a dragging motion long enough to re-order it in a large list
2) With a user dragging and the content shifting, it becomes increasingly difficult to place the item where you want

The first issue is one I didn’t spend to long on. ‘Tapping’ is a common place form of interaction on phones and is far less committal than dragging. What that then left was a way to connect tapping on the item you wanted to move, and a visual cue on how to place it.

For the purposes of my prototype these are simply blue lines but they could be styled to have instructions such as ‘move here’, or whatever else you think signifies a movement instruction. Once one of these lines is clicked, the item is moved to that position. Simple!

The following two functions can be called for items in a group list, or the groups themselves:

function moveButton(focus, target, rowend) {
    
    var selectedArea = focus.closest(target),
        selectedParent = focus.closest(target);

    //make all items inactive
    $(target).removeClass('active').addClass('inactive');
    //make selected area active
    selectedArea.removeClass('inactive').addClass('active');
    
    //make all row ends active
    $(rowend).removeClass('inactive');

    //make row ends before and after selected area inactive
    selectedParent.prev().addClass('inactive');
    selectedParent.next().addClass('inactive');

    //show cancel button
    focus.next().show();
    //fade all row ends in
    $(rowend).fadeIn();

}

function moveElement(focus, item, rowend) {
    var  movingElement = $(item + '.active');
    if(!focus.hasClass('inactive')) {

        if(movingElement.length == 1) {

            //Create an array, and add items in their new order
            var detached = [];
            detached.push(movingElement.next().detach());
            detached.push(movingElement.detach());

            //console.log(detached);
            $.each(detached, function(i, v) {
                focus.after(v);
            });

            //reset everything
            resetElements(item, rowend);

        }
    }
}

function resetElements(item, rowend) {
    $(item).removeClass('inactive').removeClass('active');
    $(rowend).removeClass('inactive').hide();
    $('.cancel-button').hide();
}
            

So the process goes like this:

The prototype is bare bones but could be extended through the following:
Modernizr – Could be used to only have the behaviour work on touch devices, for instance, if you already have default behaviour in place.
Enquire.js – A great library that allows you to execute JavaScript depending on the size of the user’s screen. Rather than targeting touch, you could have the behaviour come into effect when a user’s screen is below X amount of pixels.

View the example

Download the source code