8

I have a template:

function useIt() {
  var content = document.querySelector('template').content;
  // Update something in the template DOM.
  var span = content.querySelector('span');
  span.textContent = parseInt(span.textContent) + 1;
  document.querySelector('#container').appendChild(
    document.importNode(content, true));
}
<button onclick="useIt()">Use me</button>
<div id="container"></div>

<template>
    <div>Template used: <span>0</span></div>
    <script>alert('Thanks!')</script>
</template>

You can try the code here. This code basically copies the template(html5 templates does not render on your screen) into another div. This allows you to reuse the DOM.

Problem: The line "span.textContent = parseInt(span.textContent) + 1;" changes the template code directly. I need to manipulate the content DOM and clone it into the container, without changing the template. This is very important since if I want to reuse the code, I need it to stay the same.

I have tried multiple ways to use jQuery to mimic the above javascript code, but I can't manage to figure it out. It would be better if there is a jQuery way.

2
  • I would say the order in your code is wrong. I would try it in this order: 1. query template. 2. import node. 3. modify content. 4. append to DOM. Commented Dec 13, 2015 at 18:46
  • I am not sure if this is relevant, but would slots be useful in this context? Commented Mar 20, 2022 at 19:32

2 Answers 2

11

If you NEED to use the new <template> tag, then you are mildly stuck . . . your cleanest alternative is to use importNode to bring in the content and then modify it after it's been appended.

Assuming that the templated code is realtively small, this should happen fast enough that you would never notice the difference in approach, though, in this specific example, the alert(), would delay the change of the content, so you would see "0", until you clicked "Okay", and then it would update to "1".

The code change for that would be:

function useIt() {
    var content = document.querySelector('template').content;

    var targetContainer = document.querySelector('#container');
    targetContainer.appendChild(document.importNode(content, true));

    var $span = $(targetContainer).find("div:last-of-type").find("span");
    $span.text(parseInt($span.text() + 1));
}

If you are not married to the idea of <templates>, you could use jQuery's clone() method to do what you want to do, very easily . . . but, clone does not "see" the content of a <template>, due to the special nature of that particular element, so you would have to store the templated code some other way (JS variable, hidden div, etc.).

HOWEVER, this method will not work if you need to clone a script, the way that a <template> will. It will not trigger any script code in the "template container" element when the cloned version is created or appended. Additionally, if you store it in a hidden <div>, any script code in the "template container" element will trigger immediately on page load.

A simple version of the code for the clone() approach would look something like this:

function useIt() {
    var $content = $("#template").clone();
    var $span = $content.find("span");
    $span.text(parseInt($span.text()) + 1);

    $content.children().each(function() {
        $("#container").append($(this));
    });
}

Assuming that your template was:

<div id="template" style="display: none;">
    <div>Template used: <span>0</span></div>
    <script>alert('Thanks!')</script>
</div>

You could also move the <script>alert('Thanks!')</script> out of the template and into the script section (after you completed the "append loop"), to achive the desired alert functionality, if you wanted to.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for pointing out that jQuery does not see template tags.
that .content saved my life
10

It's an old question, but, did you try cloneNode(true)? It works on templates, as this:

var span = content.querySelector('span').cloneNode(true)

Using your full example:

function useIt() {
  var content = document.querySelector('template').content.cloneNode(true);
  // Update something in the template DOM.
  var span = content.querySelector('span');
  span.textContent = parseInt(span.textContent) + 1;
  document.querySelector('#container').appendChild(
    document.importNode(content, true));
}
<button onclick="useIt()">Use me</button>
<div id="container"></div>

<template>
    <div>Template used: <span>0</span></div>
    <script>alert('Thanks!')</script>
</template>

regards.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.