Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jquery Sortable style function with empty spots

In the interest of learning how to do this more efficiently, i'm curious to any thoughts of how to improve this or if i'm walking down the wrong road all together.

So far I have written, http://jsfiddle.net/mstefanko/LEjf8/9/

This handles basically what I want it to on a small scale.

There are some bugs and I don't feel confident at all that this is as good as it could be written, might be an idiot for not trying to latch onto jquery ui sortable. But with needing to do this without a simple list of items, and with wanting to expand this to include multiple drag and drop, I wanted to at least walk through what I needed to do to make this happen even if it was just to learn how sorting functions like these work.

The problem child,

This is all in a function called on the over event of the droppable()

I have an array of empty spots

    var emptyHolders = [];

    $('.pipeline-holder').each(function(){
        if($(this).hasClass('holder-empty')){
            var eid = $(this).attr('id');
            emptyHolders.push(eid.substring(14));
        }
    });

cid is the droppable element that you're over top of, so I find the next open slot using

   for (var i = 0; i < emptyHolders.length; i++) {
        var currentEmpty = emptyHolders[i];
        if (currentEmpty > cid) {
            nextEmpty = currentEmpty;
            i = emptyHolders.length;
        } else {
            prevEmpty = parseInt(currentEmpty);
        }
    }

If there is a an empty slot further down the list, I use a for loop to loop through moving the items around the DOM to make the space needed to drop the element.

 if (nextEmpty != null) {
        var moveMe = nextEmpty -1;

        for (var i = moveMe; i >= cid; i--) {

            var nextcount = i + 1;
            var me = $('#pipeline-rank-' + i);       
            var next = $('#pipeline-rank-' + i).parents('.pipeline-rank-row').next().find('.pipeline-holder');
            var pid = $('#pipeline-rank-' + i).find('.content-wrapper').attr('id');

            next.append($('#pipeline-rank-' + i).find('.content-wrapper'));
            next.removeClass('holder-empty');
            next.siblings('.remember-my-position-hover').html(pid);
        }
         $('#pipeline-rank-' + cid).addClass('holder-empty');
    } 

If there is not one further down the list, I do the same thing in reverse to check if there is a spot above the droppable to push items up into.

Any thoughts are extremely appreciated!

like image 288
mstef Avatar asked Apr 26 '13 19:04

mstef


1 Answers

For something like this it is probably worth manipulating DOM elements directly and keeping references to them in an array rather than using jQuery selectors. You started to do this with emptyHolders but I would do it for all the containers (droppable elements).

I'd keep two lists/arrays: one with the state before the drag and one to display. Whenever the drag goes over a new container I would first reset the state to the pre-drag state and then recompute the changed state from there and then show the new changed state. (To avoid flicker, I would not actually show the pre-drag state, just reset my internal list to it.) That way you avoid disturbing the list with the new addition as much as possible.

To make space for the new element, I suggest the following:

  • If the current element is empty, no change.
  • If the current element is not empty but there is an empty space above it, move items below the empty space up one until the current space is empty.
  • If there is no space above, then move items down, extending the list if there is no empty space in the list.

That is, assuming I understand your needs correctly. The more common case is to not allow empty spaces anywhere. All insertions add to the end of the list or the head of the list or go between two list members with no spaces added. If you drop something on the list it immediately floats up until it runs into another item or is the first item on the list.

like image 70
Old Pro Avatar answered Oct 25 '22 06:10

Old Pro