0

I am trying to clone a template of a which will be populated with data and then inserted into a table. I'm currently able to use the same .clone() function with other elements on the same page but jQuery refuses to see and clone the template (I'm guessing because its not a block element).

Here is the template:

<tr id="search_result_temp" class="template">
<td class="logo">
    <img class="logo" />
</td>
<td class="ratings">
    <p id="rating"></p>
</td>
<td class="programs"></td>
<td class="actions">
    <button id="request_info">Request Info</button>
    <button id="save_school">Save</button>
</td>
<td class="compare"></td>
</tr>

Here is the javascript code:

for(var index in results){
        var result = results[index];
        $result_listing = $("#search_result_temp").clone().removeClass('template').attr('id', result.key);
        $search_results.append($result_listing);
    }

Thanks!

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
Justin Lucas
  • 2,301
  • 14
  • 22
  • You should never use a `for...in` loop to iterate over an Array. – Nick Craver Oct 27 '10 at 22:36
  • @Nick Craver - it is perfectly ok to use forr..in to iterate over array – Lachezar Oct 27 '10 at 22:41
  • Is the template a part of the document-tree? – Dr.Molle Oct 27 '10 at 22:42
  • Yes it exists within the rest of the DOM if that's what you're asking. It is not within any other table. Its parent element would be since its only a template – Justin Lucas Oct 27 '10 at 22:43
  • What is the result that you are getting? And what is $search_results? A little more context might be useful. – Ender Oct 27 '10 at 22:48
  • Is it possible that `$("#search_result_temp")` has child elements that have own ids, which you are not reassigning new values when cloning their parent? – Lachezar Oct 27 '10 at 22:52
  • @Ender - jQuery refuses to see $("#search_result_temp") at all as a selector so there is no output. $search results is defined as: $search_results = $("table.search_results"); – Justin Lucas Oct 27 '10 at 22:59
  • @Lucho - Yes it does have child elements with their own ids such as

    . I'll play around with those elements to see if it makes a difference. Why would that affect the cloning? Also how do you highlight code in the comments? Thanks.

    – Justin Lucas Oct 27 '10 at 23:03
  • To remove/edit the child ids you could try to `...clone().find("*").remove_or_change_or_do_smt_else_with_ids(...)...` on the clone and then operate on them. To add code use ` – Lachezar Oct 27 '10 at 23:08
  • 2
    @Justin - Is your template row inside of a table, or just sitting on its own? – Ender Oct 27 '10 at 23:18
  • On its own. That was the problem. Just posted the answer. – Justin Lucas Oct 27 '10 at 23:23
  • 1
    @Lucho - no it's not, there are many reasons now to do this: http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript/3010848#3010848 – Nick Craver Oct 28 '10 at 00:11
  • @Nick counting is just not the right way to iterate through arrays or list or any collection. IMHO messing up with Array is not a good idea as well. – Lachezar Oct 28 '10 at 00:17
  • @Lucho - I don't even....you're saying you should never use a `for` loop? Also don't confuse **iteration** with **enumeration**, they're not the same. – Nick Craver Oct 28 '10 at 00:21
  • @Nick No, I am saying that `for` loop is great for counting (e.g. from 5 to 25), but it is not good to iterate on collection as Arrays or lists or others. AFAIK visiting each element of Array one after another is called iterating, not counting :-) – Lachezar Oct 28 '10 at 00:26
  • @Lucho - In an array you should use a `for` loop, to **iterate**, a `for...in` loop is for **enumerating** an object, they're not the same. For example the indexes in an array aren't guaranteed to be in order (and they aren't in order in IE). Use a `for..in` loop if you want, but don't say I didn't warn you, any JS expect will tell you it's a bad idea for this and the fact other properties will be in the mix. – Nick Craver Oct 28 '10 at 00:29
  • @Nick and @Lucho - The argument in question is an object literal which I believe satisfies both of your opinions. Lucho, I agree a for loop is for counting but when you're iterating through an array that's exactly what you're doing, counting from 0 to (array.length - 1). Nick, how would numerical indexes in an array not be in order? The values themselves might not be in order but are you saying the indexes don't go 0, 1, 2, 3... in IE ? – Justin Lucas Oct 28 '10 at 00:37
  • @Justin - that's exactly what I'm saying, that's why you don't *enumerate* with a `for in` loop. For an object this is fine, for an Array, it's not. For an example of what I mean about IE, test this: http://www.jsfiddle.net/nick_craver/fqgAh/ – Nick Craver Oct 28 '10 at 00:42
  • @Nick Yes, I agree about the IE6 poor behavior. It is safer to use `for`. (IE 7 and 8 are doing the same as IE6... that's insane!!!) – Lachezar Oct 28 '10 at 00:45
  • @Lucho: The enumeration order of objects using `for...in` is specified as being implementation specific, meaning it can be anything. What IE does is no more wrong than what any other browser does. The other problem with using `for...in` for an array is that if `Array.prototype` or `Object.prototype` has been augmented then you'll get those properties showing up when you use `for...in`. – Tim Down Oct 28 '10 at 08:18
  • Did you ever get this resolved successfully? Do you still need help with this? – jcolebrand Dec 14 '10 at 04:27
  • Yes. Thanks. The root problem was that .innerHTML will not work with table fragments. Full answer below. – Justin Lucas Dec 15 '10 at 06:21

3 Answers3

2

Found the answer. The clone() function works fine when the template <tr> is encapsulated within <table> and <div> elements. As stated below .innerHTML (which jQuery uses in clone()) does not work with table fragments. That means jQuery will not clone a <tr> if it is a root element (whose parent element is <body>). Therefore, the template should look like this(of course with an appropriate id on the <div> to be selected by jQuery):

<div>
<table>
<tr id="search_result_temp" class="template">
<td class="logo">
    <img class="logo" />
</td>
<td class="ratings">
    <p id="rating"></p>
</td>
<td class="programs"></td>
<td class="actions">
    <button id="request_info">Request Info</button>
    <button id="save_school">Save</button>
</td>
<td class="compare"></td>
</tr>
</table>
</div>
Justin Lucas
  • 2,301
  • 14
  • 22
  • 1
    If you want to know why you have to do it this way, it is due to browser limitations in setting table fragments with `.innerHTML` – staticsan Oct 28 '10 at 00:09
0
for(var index in results){
        var result = results[index];
        $result_listing = $("#search_result_temp").clone().removeClass('template').attr('id', result.key);
        $search_results.append($result_listing);
    }

correct me if I'm wrong, but why do you need to

var result = results[index];

index is already a single element of results

jcolebrand
  • 15,889
  • 12
  • 75
  • 121
0

Alternatively you can wrap the template in a hidden DIV and access the content via jQueries HTML method. On a side note, you might bump heads cloning several items with the same ID. Try use a class approach and add an identifier (Try the new HMTL5 data-* tag attribute).

Slappy
  • 4,042
  • 2
  • 29
  • 41