apratimankur
apratimankur

Reputation: 803

html5 template content (document fragment) load order on appendChild

consider the following code -->

<template id="foo">
    <script type="text/javascript">
        console.log("00000000");
    </script>

    <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>

    <script type="text/javascript">
        console.log(11111111);
    </script>
    <script type="text/javascript">
        console.log(22222222);
        var xyz = $;
        console.log(33333333);
    </script>
</template>

now on appending this to the DOM

var template = document.getElementById('foo')
var clone = document.importNode(template.content,true);
document.appendChild(clone);

gives this output in console -->

   00000000
   11111111
   22222222
   Uncaught ReferenceError: $ is not defined

So the question in general is -->

How to properly load into DOM, an html <template> that has an external script (like jQuery in this case), followed by an inline script having some dependency on it.

Also - this does not happen if template tag is removed -->

   <script type="text/javascript">
        console.log("00000000");
    </script>

    <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>

    <script type="text/javascript">
        console.log(11111111);
    </script>
    <script type="text/javascript">
        console.log(22222222);
        var xyz = $;
        console.log(33333333);
    </script>

How in the latter case, does the browser download it synchronously?

Is it possible to have blocking script download (line by line) in the former case (with template) ?

Upvotes: 0

Views: 2589

Answers (2)

Boyardee
Boyardee

Reputation: 324

Here's how I handle it in my application (with jQuery):

//Load the template from an external file and append it to the HEAD of the document
$.get("/path/to/your_external_template_file.html", function (html_string) {
    $('head', top.document).append(
        new DOMParser().parseFromString(html_string, 'text/html').querySelector('template')
    );
}, 'html');

//Locate the template after you've imported it
var $template = $("#top_template_element_id");

//If you want to reuse the content, be sure to clone the node.
var content = $template.prop('content').cloneNode(true);

//Add a copy of the template to desired container on the page
var $container = $('#target_container_id').append(content);

Upvotes: 0

CoderPi
CoderPi

Reputation: 13211

The problem is that the script is loaded async. That means that it start to load the script from the web, but continues running the code below. So in that case it will execute code below without having loaded jQuery yet.

You only need to load it once, so you could do it at the start, and only once:

var template = document.getElementById('foo')
var clone = document.importNode(template.content,true);
document.body.appendChild(clone);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<template id="foo">
  <script type="text/javascript">
    console.log(00000000);
  </script>

  <script type="text/javascript">
    console.log(11111111);
  </script>
  <script type="text/javascript">
    console.log(22222222);
    var xyz = $;
    console.log(33333333);
  </script>
</template>

Another option would be to make sure code below is only executed once the file is loaded:

var template = document.getElementById('foo')
var clone = document.importNode(template.content, true);
document.body.appendChild(clone);
<template id="foo">
  <script type="text/javascript">
    console.log(00000000);
  </script>

  <script type="text/javascript">
    function scriptOnload() {
      console.log(11111111);
      console.log(22222222);
      var xyz = $;
      console.log(33333333);
    }
  </script>

  <script onload="scriptOnload()" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</template>

Upvotes: 0

Related Questions