views:

128

answers:

2

I have two ordered lists next to each other.

When I take a node out of one list I want to insert it alphabetically into the other list. The catch is that I want to take just the one element out and place it back in the other list without refreshing the entire list.

The strange thing is that when I insert into the list on the right, it works fine, but when I insert back into the list on the left, the order never comes out right.

I have also tried reading everything into an array and sorting it there just in case the children() method isn't returning things in the order they are displayed, but I still get the same results.

Here is my jQuery:

function moveNode(node, to_list, order_by){

    rightful_index = 1;
    $(to_list)
        .children()
        .each(function(){
            var ordering_field = (order_by == "A") ? "ingredient_display" : "local_counter";

            var compA = $(node).attr(ordering_field).toUpperCase();
            var compB = $(this).attr(ordering_field).toUpperCase();
            var C = ((compA > compB) ? 1 : 0);
            if( C == 1 ){
                rightful_index++;
            }
        });

    if(rightful_index > $(to_list).children().length){
        $(node).fadeOut("fast", function(){
            $(to_list).append($(node));
            $(node).fadeIn("fast");
        }); 
    }else{
        $(node).fadeOut("fast", function(){
            $(to_list + " li:nth-child(" + rightful_index + ")").before($(node));
            $(node).fadeIn("fast");
        });
    }

}

Here is what my html looks like:

<ol>
<li ingredient_display="Enriched Pasta" ingredient_id="101635" local_counter="1">
     <span class="rank">1</span>
     <span class="rounded-corners">
          <span class="plus_sign">&nbsp;&nbsp;+&nbsp;&nbsp;</span>
          <div class="ingredient">Enriched Pasta</div> 
          <span class="minus_sign">&nbsp;&nbsp;-&nbsp;&nbsp;</span>
     </span>
</li>
</ol>
A: 

I would get the .text() of each element firs, then put it on an array, sort the array, then move each element where indexes of the SORTED matches the UNSORTED.

and I am too lazy to write the code for that and test it right now :) but just a thought of my way of approaching it.

Val
+3  A: 

I have created a jsFiddle with working code to solve this problem. I am including the code here as well just in case jsFiddle goes belly up in the distant future:

<ol class="ingredientList">
    <li class="ingredient">Apples</li>
    <li class="ingredient">Carrots</li>
    <li class="ingredient">Clams</li>
    <li class="ingredient">Oysters</li>
    <li class="ingredient">Wheat</li>
</ol>
<ol class="ingredientList">
    <li class="ingredient">Barley</li>
    <li class="ingredient">Eggs</li>
    <li class="ingredient">Millet</li>
    <li class="ingredient">Oranges</li>
    <li class="ingredient">Olives</li>
</ol>​

and the jQuery:

$(".ingredient").click(function(){
    var element = $(this);
    var added = false;
    var targetList = $(this).parent().siblings(".ingredientList")[0];
    $(this).fadeOut("fast", function() {
        $(".ingredient", targetList).each(function(){
            if ($(this).text() > $(element).text()) {
                $(element).insertBefore($(this)).fadeIn("fast");
                added = true;
                return false;
            }
        });
        if(!added) $(element).appendTo($(targetList)).fadeIn("fast");
    });
});​

I stripped your HTML down for the sake of brevity, so you will want to modify my code to match yours. Also, if you are going to use user defined attributes (which are not valid HTML and not officially supported by any browser...though it also won't hurt anything....probably), I recommend prefixing them with "data-" to conform with the HTML5 Custom Data Attribute specification. So "ingredient_id" would become "data-ingredient_id". While this is not yet supported on any current browser as HTML5 has not been finalized, it is safer and more robust than just defining your own attributes. And once HTML5 is finalized, your attributes will be fully supported.

Bradley Mountford
@Bradley I've tried out your method and it does work when you just use .text(). However, mine also works when you use .text(). Ours both break when I use .attr(). I've stopped using the user-defined attributes and just tried playing around with the `id` attribute and I still get the same strange behavior. A debug tells me that .children() is, in fact, iterating in the correct order. This is so frustrating.
Dex
I do need to sort other ways than alphabetically. I need to also be able to sort by that `local-counter` field in my original HTML.
Dex
I just updated the jsFiddle to order by .attr() and it seems to work. http://jsfiddle.net/VQu3S/9/
Bradley Mountford
I think I just figured out what was wrong. Such a n00b mistake too! When comparing the data-local_counter, I did not parseInt(), so it was doing a string compare. Ugh. I think this has fixed it though, and user-defined attributes don't appear to be a problem in Safari or FF on OS X.
Dex