Question

I've found good posts on good practices inserting dom elements using jquery like this, this and this

It's ok when you just need to insert a few elements, but it seems to me that these option are very bad from the point of view of maintainability (Code is repeated twice, thus if any change is needed it needs to happen twice then it becomes very prone to error ),

This is (just a small part) what I've got

<script type="text/javascript">
var phnFragment = "<tr><td align=\"right\">Telephone:</td><td colspan=\"2\"><select name=\"select\" size=\"1\"style=\"width: 100px;\"><option>-- Choose --</option><option>Home</option><option>Mobile</option><option>Work</option></select><input type=\"text\" size=\"20px\" /></td></tr>";
    $(document).ready(function() {
    $('#addmorephones').click(function() {
                $("#phones").append(phnFragment);
            });
    });
</script>
....
....
<tr id="phones">
        <td align="right">Telephone:</td>
        <td colspan="2"><select name="select" size="1"
            style="width: 100px;">
            <option>-- Choose --</option>
            <option>Home</option>
            <option>Mobile</option>
            <option>Work</option>
        </select><input type="text" size="20px" /> <a href="javascript:void(0);" id="addmorephones">[+]</a>
        </td>
    </tr>

Is there a better way to accomplish this? Is there a way to tell jquery to copy part of the dom tree and use it as fragment to insert?

Would love to learn alternatives

Was it helpful?

Solution

Is there a way to tell jquery to copy part of the dom tree and use it as fragment to insert?

Yes: clone. (You don't even really need jQuery for it; cloneNode is part of the DOM API.) If you have any id values in what you clone, you'll need to iterate over the result changing them, of course, since ids have to be unique. But it's perfect for things like table rows and the like.

On page load, you can grab one of the real ones, clone it (without attaching it to the document), cleanse it of anything you don't need, and then just keep cloning that model. Helps keep your JavaScript somewhat decoupled from your markup.

Example:

HTML:

<table>
  <tbody>
    <tr><td>I'm a row in the table</td></tr>
  </tbody>
</table>

JavaScript:

jQuery(function($) {
  var counter = 10,
      rowModel;

  // Get the row model, clone it, remove the
  // content we'll replace anyway.
  rowModel = $("tr:first").clone();
  rowModel.find("td:first").empty();

  // Do our first tick
  tick();

  // Use the model to append to the table
  function tick() {
    var clone = rowModel.clone();

    clone.find("td:first").html("Added at " + new Date());
    $("tbody:first").append(clone);

    // Again?
    if (--counter > 0) {
      setTimeout(tick, 500);
    }
  }

});

Live copy

Obviously that's a quick-and-dirty, but you get the idea. If you use data-xyz attributes (allowed in HTML5), names, classes, etc., you can avoid tying your code too closely to your structure.

OTHER TIPS

In this case, you could grab the contents of #phones during the ready event:

$(document).ready(function() {
    var phnFragment = $("#phones").html();

    $('#addmorephones').click(function() {
        $("#phones").append(phnFragment);
    });
});

If you need to copy more complex information (like events), you can use the .clone() method:

$(document).ready(function() {
    var $phnFragment = $("#phones").children().clone();

    $('#addmorephones').click(function() {
        $("#phones").append($phnFragment.clone());
    });
});

T.J. has a great answer if you've got existing markup you want to reuse. You can also use the text/html script type to put your content in markup as a template, as demonstrated here:

http://ejohn.org/blog/javascript-micro-templating/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top