JQuery clone table and add to end of last table, table becomes incorrect order

825 views Asked by At

Problem I'm trying to clone a table, and successfully have. But the order of it isn't correct, and I cannot figure out why it's not displaying in the correct order.

JQuery:

    data = [1,2,3];
    for (var i=0; i<data.length; i++) {
        //console.log(ike_transform[i]);
        path = data[i];
        console.log(path);

        if (i!=0) { // clones table for next iteration
            $("#phase_1_tranforms_tables").clone().insertAfter("div.div_transform:last");
        }

        $("#transform_num").html(i+1); // table #
    }

HTML:

 <div id="div_transforms" class="div_transform">
     <table class="table table-bordered table-condensed" id="phase_1_tranforms_tables">
        <tr>
            <th rowspan="4" id="transform_num"></th>
            <th class="second_head">$('Authentication')</th>
            <td id="sel_pu_xform_auth"></td>
        </tr>
        <tr>
            <th class="second_head">$('Encryption')</th>
            <td id="sel_pu_xform_encr"></td>
        </tr>
        <tr>
            <th class="second_head">$('SA Life')</th>
            <td id="sel_pu_xform_sa_life"></td>
        </tr>
        <tr>
            <th class="second_head">$('Key Group')</th>
            <td id="sel_pu_xform_key_group"></td>
        </tr>
     </table>
 </div>

Screenshot of current: enter image description here

Desired Result: Is exactly what it is right now, but the tables are not in the right order. Should be Table 1, Table 2, Table 3, etc. Please someone help me reverse this madness!

UPDATE Here is the fiddle code for it. I had to change some HTML because it wouldn't like the Cheetah template and certain weirdness going on. http://jsfiddle.net/tylerip87/xtb51wed/4/

I have no new screenshot for it since my work server decided to poop out today. But the jsfiddle shows the table using .appendTo as 3, 1, 2.

1

There are 1 answers

8
David Thomas On BEST ANSWER

Without running your code, I'd suggest using:

$("#phase_1_tranforms_tables").clone().appendTo("div.div_transform:last");

Because your original code was doing precisely as you asked, and inserting your cloned-tables immediately after the div.div_transform:last element, and therefore before the previously-inserted table element(s), which looked like the code was somehow reversing the order of what it was doing.

With reference to your problems with appendTo(), yeah. That was the fault of using an id selector to update the text of an element. Essentially:

  1. an id selector (getElementById('idString'), $('#idString')) return only the first matching element (by design) since there should only ever be one element, or none, with any given id.
  2. the reason that 1 appeared in the right place is because cloning only occurs after the first loop (when i != 0), so:
    • the element with id='transform_num' is selected, updated to i + 1 (1).
    • the first table is cloned, and the clone appended after that first table (keeping the number 1).
    • the first table-element (the original table) has its #transform_num element selected and updated to i + 1 (2), the clone retains the number of 1 (because of the invalid duplicate id).
    • the first table-element is cloned again, the clone is appended to the parent (this clone has the number 2).
    • the first table-element's #transform_num is selected (again) and updated to i + 1 (3).

The order of the clones is correct, the use of a multiple id (as always!) causes (unnecessary) problems. The solution I've implemented is:

var data = [1, 2, 3],
    path;
for (var i = 0; i < data.length; i++) {
    // and always declare local variables to avoid the global name-space:
    path = data[i];

    if (i != 0) { // clones table for next iteration
        $("#phase_1_tranforms_tables").clone().appendTo("div.div_transform");
    }
    // and the error was here, using an 'id' that was duplicated
    // and therefore invalid, and incrementing only the *first*
    // element matched by the id selector:
    // $("#transform_num").html(i + 1);

    // Instead, I changed 'id' to a 'class' (so: valid), and
    // selected only the last element with that given class:
    $('div.div_transform .transform_num').last().text(i + 1);
}

JS Fiddle demo.

Alternatively, you could simply use a class to select all the appended elements and update the text (of all) according to its position in the collection:

// Selecting all the elements and updated each of their text,
// using the anonymous function available to the method, and the
// first argument (name is irrelevant, but it's always the index
// of the element amongst the returned collection):
$('div.div_transform .transform_num').text(function (index) {
    return index + 1;
});

JS Fiddle demo.

Of course, you could just use CSS (using a class for the <p>, again):

div.div_transform {
    counter-reset: transform_num;
}

table p::before {
    counter-increment: transform_num;
    content: counter(transform_num);
/* the above is important, below is aesthetic; adjust to taste */
    display: block;
    width: 1em;
    text-align: center;
    font-weight: bold;
}

JS Fiddle demo.

References: