3

I'm sorting a table using jQuery, roughly following the code found here. The code sketch is as follows:

$('.sort-table').click(function(e) {
    // cache objects
    $table  = $('#sort-table'),        // cache the target table DOM element
    $rows   = $('tbody > tr', $table); // cache rows from target table body

    // sort items
    $rows.sort(<my_predicate_function(a,b){...}>);

    // assign to table - what is going on?
    $rows.each(function(index, row){
        $table.append(row);  // <-- how come $table remains the same size?                  
    });
});

While the code works fine, I'm puzzeled by the code that appends the rows back to the table, which simply iterates over the sorted rows, appending each at the end of $table.

At no stage did we emtpy $table from its previous children.

  • Since $table was never emptied, how come $table remains the same size?
  • Does append() also enforces uniquness in the target container?
Community
  • 1
  • 1
bavaza
  • 10,319
  • 10
  • 64
  • 103
  • 2
    In your example code the array containing the rows actually contains references to them, rather than copies or HTML (as you may be expecting), so when it appends them to the table it is actually moving the existing rows to the end, one-by-one. – Reinstate Monica Cellio Dec 01 '16 at 11:30
  • 2
    http://api.jquery.com/append/ - "You can also select an element on the page and insert it into another: If an element selected this way is inserted into a single location elsewhere in the DOM, it will be moved into the target (not cloned)." it looks like it wont explicitly look for uniqueness in terms of the content but it just moves the element. – Luke Kot-Zaniewski Dec 01 '16 at 11:33
  • Related: [Sorting a list by data-attribute](/q/32199368/4642212). – Sebastian Simon Nov 20 '22 at 05:45

2 Answers2

2

This is simply how the DOM works. You can't have an element in two different places. If an element is already in a document and you put it somewhere else, it will be moved from its current position. It is, I suppose, a little like a Set, but that is not how it is specified. So it's not removing duplicate objects, because there never are duplicate objects: it's simply moving the same object, which can only exist in one place.

From the MDN documentation for the underlying method, Node.appendChild:

The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position (there is no requirement to remove the node from its parent node before appending it to some other node).

If you want to duplicate elements, you need to clone them (DOM, jQuery).

lonesomeday
  • 233,373
  • 50
  • 316
  • 318
  • Wow! While I can see the appeal of this approach, I would expect it to be on the first page of any decent DOM tutorial - it is very different from any other model I'm familiar with (speaking as a web newbie, that is :-)) – bavaza Dec 01 '16 at 11:48
  • @bavaza It's not much different to a standard node-tree model. – lonesomeday Dec 01 '16 at 13:20
  • Maybe, but that was the first time I've encountered an 'append()' method that actually has 'move()' semantics. – bavaza Dec 01 '16 at 14:06
-2

As from JQuery doc for .append()

Description: Insert content, specified by the parameter, to the end of each element in the set of matched elements.

As from MDM doc for Set

The Set object lets you store unique values of any type, whether primitive values or object references.

Nothing gets removed. You only will replace the existing element if it's exactly the same, which is the case in your example.

Herr Derb
  • 4,977
  • 5
  • 34
  • 62
  • 1
    nice. Where does it say `$('tbody > tr', $table)` returns a JS `Set`? – bavaza Dec 01 '16 at 11:36
  • It doesn't. This will only return a Collection. But with `$table.append(row); // <-- how come $table remains the same size?` you add the same element you've take from the set into the same set again. – Herr Derb Dec 01 '16 at 11:37
  • For this to work, `$table` must be treated as a set, not as an e.g. array. Otherwise duplicates **are** allowed. Is this specified somewhere? – bavaza Dec 01 '16 at 11:39
  • 2
    It's not a `Set`. – lonesomeday Dec 01 '16 at 11:42