Search code examples
jquerysortingappendappendchild

Sort of li's which contain ol's or ul's fails with HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy


I am creating rich text with CKEditor and embedding the resulting html into div's contained within li's within an unordered list (ul). I sort the li's using jQuery and various comparisons. When the rich text itself contains ul's or ol's, which CKEditor will allow, the sort fails with the message in FF Firebug:

"HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy on line"

and cites this code from jQuery:

append: function() {
    return this.domManip(arguments, true, function( elem ) {
        if ( this.nodeType === 1 || this.nodeType === 11 ) {
            this.appendChild( elem );
        }
    });
}, 

When the html does not contain any ul's or ol's, the sort works fine.

Here is the HTML context:

An unordered list where each li is classed "RetailerSearchSectionLine" and contains div's containing the rich text as html.

Here is one of the jQuery sort functions which fails:

var TransferArray = $(".RetailerSearchSectionLine").toArray().sort(function(a, b)
{
    var distance1 = $(a).data("DistanceFromReferenceLocation");
    var distance2 = $(b).data("DistanceFromReferenceLocation");
    return (distance1 - distance2);
});
$("#RetailerSearchSectionBody ul").append(TransferArray);

Any suggestions? I am thinking of sorting keys to the array and then rearranging the ul based on the sorted result. But that is a lot of work which actually may not work if there is some basic issue I am not seeing with lists within lists.


Solution

  • The line

    $("#RetailerSearchSectionBody ul").append(TransferArray);
    

    doesn't look right because $("#RetailerSearchSectionBody ul") may select a collection (including child ULs) rather than a unique element.

    The following should safely select a unique element :

    $("#RetailerSearchSectionBody").children("ul").eq(0).append(TransferArray);
    

    If that doesn't work, then it's arguably more normal to perform the sort on the original jQuery-wrapped elements rather than breaking out into a genuine array, as follows :

    Array.prototype.sort.call($(".RetailerSearchSectionLine"), function(a, b) {
        var distance1 = $(a).data("DistanceFromReferenceLocation");
        var distance2 = $(b).data("DistanceFromReferenceLocation");
        return (distance1 - distance2);
    }).each(function(i, item) {
        $("#RetailerSearchSectionBody").children("ul").eq(0).append(item);
    });
    

    It's probably academic which approach you adopt because the sort itself appears not to be the problem. Anyway, this is something else you could try.