2

I have a UL-LI e.g.

<ul>
    <li id="1">item-1</li>
    <li id="2">item-2</li>
    <li id="3">item-3</li>
    <li id="4">item-4</li>
</ul>

I would like to move one of the items to another position in the list. e.g. item-2 to AFTER item-4.

Normally I can do this by deleting the item and then appending it after another.

But I would like to do this to happen visually with animation. As in, item-2 descends to after item-4.

How can I achieve this?

Phil
  • 13,875
  • 21
  • 81
  • 126

2 Answers2

4

IDs should not start with numbers...

$('#two').slideUp(500, function () {
    $('#four').after(this);
    $(this).slideDown(500);
});

Here is a demo: http://jsfiddle.net/jasper/8JFBA/

Or if you always want to add the element to the end:

$('#two').slideUp(500, function () {
    $('ul').append(this);
    $(this).slideDown(500);
});

Here is a demo: http://jsfiddle.net/jasper/8JFBA/1/

Update

Ok, so if you want the element to slide to it's new location here ya go:

//absolutely position the element and give it a top property so it doesn't go to the top of the container
$('#two').css({ position : 'absolute', top : $('#two').position().top });

//now get the offset to the bottom of the list by getting the top offset and height for the last list-item
var lastOffset = ($(this).children().last().position().top + $(this).children().last().height());

//now animate the element to the new position
$('#two').animate({ top : lastOffset }, 1000, function () {

    //when the animation is done, re-add the element to the new position in the list and reset it's position and top values
    $(this).appendTo('ul').css({ position : 'relative', top : 0 });
});

And a demo: http://jsfiddle.net/jasper/8JFBA/3/

Update

You can animate not only the element being moved to the end of the list but you can animate the rest of the list items as they move up:

var $LIs     = $('ul').children(),
    liHeight = 20;
$LIs.on('click', function () {
    
    var index      = ($(this).index()),
        $LIsAfter  = $LIs.filter(':gt(' + index + ')');
    
    console.log(index);
    
    $(this).css({ position : 'absolute', top : $(this).position().top });
    
    $.each($LIsAfter, function (i) {
        $(this).css({ position : 'absolute', top : ((i + index + 1) * liHeight) });
    });
    
    $(this).stop(true, true).animate({ top : (($LIs.length - 1) * liHeight)}, 1000, function () {
        $(this).appendTo('ul').css({ position : 'relative', top : 0 });
    });
    
    $.each($LIsAfter, function (i) {
        $(this).stop(true, true).animate({ top : ((index + i) * liHeight) }, 1000, function () {
            $(this).css({ position : 'relative', top : 0 });
        });
    });
});

Here is a demo: http://jsfiddle.net/jasper/8JFBA/8/

This isn't quite complete, there is still a bug or two, but it should help get anyone started on the idea.

Community
  • 1
  • 1
Jasper
  • 75,717
  • 14
  • 151
  • 146
  • I think, OP wants it to "item-2 descends to after item-4." slide is just show and hide.. Imagine you have 10 elements.. and I slideUp one and slideDown ten, Doe it give the effect of descending? – Selvakumar Arumugam Mar 02 '12 at 19:43
  • Jasper, this works as it is however it is not exactly what I wanted to know. Thank you. Although, how do you think we can make the item descend? Any ideas? – Phil Mar 02 '12 at 19:49
  • @Phil I think my **update** crossed your comment in transit. Check-out the **update** to my answer and see if that's what you're looking for. – Jasper Mar 02 '12 at 19:52
  • @Jasper, I can not thank you enough for your help. Greater than that, the explanations have been even better. Now not only I can do this but also I have the 'logic' and understanding of the matter. Really really thank you so very much. If you have the time-chance, could you please tell why IDs should not start with numbers? – Phil Mar 02 '12 at 20:25
  • @Phil The specifications that browsers use to build their code say that there is a specific way to create an ID (browsers handle improperly formatted IDs pretty well though). Here is a link to a great StackOverflow answer that explains how to properly format an ID in a HTML document: http://stackoverflow.com/a/79022/752738. – Jasper Mar 02 '12 at 20:42
  • @Phil I added another **update** to my answer (just for fun). Check-it-out, it's kind of a cool way to animate the changing of the list: http://jsfiddle.net/jasper/8JFBA/8/ – Jasper Mar 02 '12 at 21:03
4

I tried to implement a smoother transition when you descend and below is my version..

You need to try out the demo to understand how it works.. Select value from the drop down and hit Descend to see the animation.

DEMO

Edit: Updated top position of $from before addClass('active') to start from the exact position and not top: 0px. Thanks to Jasper for finding this issue.

var $from = $('#from');
var $to = $('#to');

$('button').click (function () {
   var from = $from.val();
   var to = $to.val();

   var $li = $('ul li');
   var $fromEl = $('#' + from);
   var $toEl =  $('#' + to);

    //only descending    
   if (from == to || $li.index($fromEl) > $li.index($toEl)) return;

   var destX = $toEl.position().top;

   $toEl.after('<li id="tmpLi2"></li>');

   $('#tmpLi2').animate({height: $fromEl.outerHeight()}, 1000);

     //add a blank li for smooth animation
     $fromEl
         .after('<li id="tmpLi1">&nbsp;</li>')
         .css ('top', $fromEl.position().top)
         .addClass ('active' )
         .animate({
                top: (destX)
             },
             1000,
             function() {
                $toEl.after(this);
                $('#tmpLi2').remove();
                $(this).removeClass('active');
          });

    $('#tmpLi1').slideUp(function() { $(this).remove()});

});
Selvakumar Arumugam
  • 79,297
  • 15
  • 120
  • 134
  • Thank you very very much as well. This is excellent. Really smooth and beautiful! Thank you so very much @SKS. – Phil Mar 02 '12 at 21:08
  • If you give the `$fromEl` element a `top` that is equal to the current `.position().top` of the element when you add the `active` class then it will animate from it's current vertical position to the selected end position rather than always starting from `top : 0`. – Jasper Mar 02 '12 at 21:21
  • Giving each list-item a `top` property before starting the animations seems to fix it as well: `var $li = $('ul li').each(function () { $(this).css('top', $(this).position().top); });`. http://jsfiddle.net/jasper/QKS8c/3/ – Jasper Mar 02 '12 at 21:25
  • @Jasper aaww I see.. I was trying this is in FF and it worked fine there.. now trying it out in IE and it breaks.. Thanks for pointing out.. Let me fix this. – Selvakumar Arumugam Mar 02 '12 at 21:25