Using jQuery to re-order and animate list items?
Asked Answered
S

3

13

So, I've got a list of items, something like:

<ul id="listHolder">
    <li id="l1">List item 1</li>
    <li id="l2">List item 2</li>
    <li id="l3">List item 3</li>

etc. An ajax call is being fired periodically, and I may need to re-order the list (by making one of the lower items become the first one in the list). That's easy to do just by changing the HTML of #listHolder, but I would like to animate it so the appropriate item moves up the page to the right place, and the others move down.

I've got no idea where to start =/

NB. It doesn't have to be a list: a div or any other element would be fine.

Shithead answered 14/11, 2011 at 15:4 Comment(0)
S
19

Okay, I've done it - it was simpler than I imagined.

http://jsfiddle.net/Vyhph/

Note that if you click more than one list object inside of a second, everything goes wrong. You could easily stop this but it won't be an issue for me.

$("li").live("click", function() {
    var $myLi = $(this);
    var $myUl = $(this).parent();
    var listHeight = $myUl.innerHeight();
    var elemHeight = $myLi.height();
    var elemTop = $myLi.position().top;
    var moveUp = listHeight - (listHeight - elemTop);
    var moveDown = elemHeight;
    var liId = $myLi.attr("id");
    var enough = false;
    var liHtml = $myLi.outerHTML();

    $("li").each(function() {
        if ($(this).attr("id") == liId) {
            return false;
        }
        $(this).animate({
            "top": '+=' + moveDown
        }, 1000);
    });

    $myLi.animate({
        "top": '-=' + moveUp
    }, 1000, function() {
        $myLi.remove();
        var oldHtml = $myUl.html();
        $myUl.html(liHtml + oldHtml);
        $myUl.children("li").attr("style", "");
    });
});

(function($) {
    $.fn.outerHTML = function() {
        return $(this).clone().wrap('<div></div>').parent().html();
    }
})(jQuery);
Shithead answered 14/11, 2011 at 16:19 Comment(1)
awesome, glad you have something that works for you! Sorry I didn't have more time to code up my idea. Sidenote, put the code on stackoverflow.com as well. That way your answer will be available as long as the site is up. jsfiddle may change their access policies at any time.Gratiana
G
4

Personally, I would grab jQuery UI Sortable functionality and trigger the events on ajax success. take a look at this documentation and let me know if you like the idea.

Gratiana answered 14/11, 2011 at 15:10 Comment(3)
I'm happy with anything that will work. So turn the list into a .sortable(), then animate the objects "manually", as it were? I'll give it a shot.Shithead
Go it, see my answer below. Although I didn't make them sortable in the end, you still pointed me in the right direction. Cheers.Shithead
Is there a way to simulate the reorder of list items automatically, without the user dragging and dropping?Approximation
C
0

I didn't really like the idea of cloning elements, and I was trying to build a leaderboard visualization, not really wanting to change the DOM, so I did it a different way using data attributes and some basic math.

html:

        <ol id="leaderboard">
            <li class="leaderboarditem" data-key="A" data-rank="0"><span class="tag">A</span><span class="tagvalue">0</span></li>
            <li class="leaderboarditem" data-key="B" data-rank="1"><span class="tag">B</span><span class="tagvalue">0</span></li>
            <li class="leaderboarditem" data-key="C" data-rank="2"><span class="tag">C</span><span class="tagvalue">0</span></li>
        </ol>

style:

        .tag, .tagvalue { display: inline-block; }
        .tag { padding-left: 1em; width: 50%; font-weight: bold; background-color: rgb(235, 235, 235); }
        .tagvalue { border-left: 10px solid rgb(235, 235, 235); border-right: 10px solid rgb(235, 235, 235); border-top: 50px solid white; border-bottom: 50px solid white; padding-left: 1em;padding-right: 1em; }
        .leaderboarditem { display: block; width: 100%; font-size: 67pt; line-height: 119pt; font-weight: bold; position: relative; top: 0px; left: 0px; }

(the key thing in the style is position: relative and display: block)

javascript:

function (f, msg) {
    var leaderboard, key_count, key, value, tag, tag_value, list_item;

                console.log(JSON.stringify(msg));

                leaderboard = {
                    element : $('#leaderboard'),
                    data : []
                };

                key_count = 0;
                for (key in msg) {
                    ++key_count;
                    value = msg[key];

                    list_item = $('.leaderboarditem[data-key=' + key.toUpperCase() + ']');
                    tag_value = list_item.find('.tagvalue').text(value);

                    leaderboard.data.push({ k: key.toUpperCase(), v: value, item: list_item });
                }

                leaderboard.data.sort(function (a, b) {
                    var a_value = a.v;
                    var b_value = b.v;
                    return b_value - a_value;
                });

                leaderboard.data.forEach(function(datum, rank) {
                    var old_rank, line_height, move_distance;

                    old_rank = datum.item.data('rank');

                    if (old_rank != rank) {
                        line_height = datum.item.height();
                        move_distance = (line_height * rank) - (line_height * old_rank);

                        datum.item.animate(
                            {'top' : '+=' + move_distance },
                            1e3,
                            function () {
                                datum.item.data({ 'rank' : rank });
                            }
                        );
                    }
                });

            }
        }
Codee answered 2/1, 2013 at 16:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.