Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using jQuery to Dynamically Insert Into List Alphabetically

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>
like image 623
Dex Avatar asked May 22 '10 02:05

Dex


1 Answers

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.

Edit - As John pointed out in the comments, this will not work if you need to support UTF-8 characters. In this case you need to use String.prototype.localeCompare() (make sure you check that the browser supports it as per the documentation). So that code would look something like this:

$(".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().localeCompare($(element).text()) > 0) {
                $(element).insertBefore($(this)).fadeIn("fast");
                added = true;
                return false;
            }
        });
        if(!added) $(element).appendTo($(targetList)).fadeIn("fast");
    });
});

Here is an updated Fiddle implementing localeCompare.

like image 150
Bradley Mountford Avatar answered Oct 06 '22 14:10

Bradley Mountford