13

Is it possible to have nested JavaScript template tags e.g.

<script id="Product" type="text/html">
    <div class="product">
        ....
        <div class="features">
            <script id="Features" type="text/html">
                <div class="feature">
                    ...
                </div>
            </script>
        </div>
        ...
    </div>
</script>

When the template "Product" is evaluated the feature template is now available as a template that I can call when I'm ready.

When I try this method in my browser, I notice some elements appear in the wrong order as if I forgot an end tag somewhere.

However when I remove the nested template (Feature) it is all good ...

Wondering if there was proper way of achieving this.

2
  • 2
    What templating engine are you using? Templating like that is not supported out-of-the-box by browsers. The contents of a script element are script code, not HTML markup. Commented Jun 12, 2011 at 14:53
  • Yes, it is possible in XHTML Commented Jan 1, 2020 at 17:17

7 Answers 7

17

You can't nest script tags. The way script tags work, the browser reads the opening tag and then starts building up a string of the code therein without interpreting that code at all. It stops doing that the first time it sees the exact sequence < / s c r i p t >. The browser will always stop at the first of those it finds, and crucially it ignores any intervening opening tag sequence, like < s c r i p t >. This is because the browser doesn't parse the script code, that's not its job. It's a separation of concerns thing. (script tags probably shouldn't be tags at all, but rather something more like a CDATA structure. But they're what we have.)

E.g., from the browser's point of view:

<script id="Product" type="text/html">              SCRIPT STARTS HERE
    <div class="product">                           SCRIPT CODE CONTINUES
        ....                                        SCRIPT CODE CONTINUES
        <div class="features">                      SCRIPT CODE CONTINUES
            <script id="Features" type="text/html"> SCRIPT CODE CONTINUES (*NOT* START OF SCRIPT)
                <div class="feature">               SCRIPT CODE CONTINUES
                    ...                             SCRIPT CODE CONTINUES
                </div>                              SCRIPT CODE CONTINUES
            </script>                               SCRIPT ENDS
        </div>                                      ENDING `div` TAG (probably mis-matched)
        ...
    </div>
</script>                                           MIS-MATCHED ENDING `script` TAG

Now, if you're using a server-side templating engine of some kind that will replace those script tags with markup and then send the updated markup to the browser, then it's up to the templating engine whether it supports nesting. Browsers do not.

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

Comments

1

You can use <style type="text/html"></style> or <noscript></noscript> to wrap your <script></script> tag.

I think <noscript> is better than <style>

example:

<noscript id="s">
  <div class="r">
    <p>{%= o.rand %}</p>
    <script>
      console.log('sdf');
    </script>
  </div>
</noscript>

<style id="s" type="text/html">
  <div class="r">
    <p>{%= o.rand %}</p>
    <script>
      console.log('sdf');
    </script>
  </div>
</style>

1 Comment

this only works for me because I'm using angularjs. I'm concatenating/minifying all my template html files into one file (like you would for js/css) but for files that already have templates I cant nest them. Thanks to this tip can make them noscript instead, and make a custom directive for that instead of script to invoke $templateCache 'manually', and seems to work exactly how individual-html+<script> did before, ta
0

Are okay with using jQuery? If so, this very possible (and even, dare I say, common):

http://blog.reybango.com/2010/07/12/jquery-javascript-templates-tutorial-nesting-templates/

12 Comments

That blog post shows a template being called from another template. Not a template definition nested inside another template definition as shown in the OP.
@Mike, that's how you nest templates.
@Kon, you are misusing the term "nesting". From thefreedictionary.com/nesting "5. Computer Science A set of data contained sequentially within another."
@Kon, agreed. You and the author of that blog post should both use the term "call" or "render" instead of "nest" which is used for textual containment in source code, usually to imply that the nested inherits the lexical scope of the container. Neither the example code in the OP nor that in the blog post show textual containment or scope inheritance -- only a call relationship.
@Mike, you are picking on something very insignificant for no good reason. Renegare has a simple problem - how to show a list of features inside a list of products - that is nesting one list within another. So the simple solution is to call a template from within a template - this is what's commonly referred to as nesting. Whether you like its use/misuse or not, that's what it's referred to as. So if you're not going to help the OP with the problem, get over it, move on, go pick a meaningless argument with someone else now.
|
0

Sometimes I think I want nested scipt tags for templating, but this is what you have to do instead:

Script 1

 <script id="Product" type="text/html">
     <div class="product">
         ....
         <div class="features">
             <!-- INSERT FEATURES HERE -->   
         </div>
         ...
     </div>
 </script>

Script 2

 <script id="Product_Features" type="text/html">
     <div class="feature">

     </div>
 </script>

You can 'namespace' the ID if you really want, to indicate it is a 'child' template. This makes it clearer is it not intended to be used by itself (obviously this is up to you if it makes sense or not).

After reading T.J.s answer this became the only obvious alternative to what I originally thought I wanted (nested scripts).

However, you probably don't need nested templates unless you need to make a choice as to which 'child' template is used. If there's only one possible layout for the child template then just use a 'foreach' according to your template engine.

Comments

0

Yes, it is possible to have nested <script> tags (with XHTML application/xhtml+xml):

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>XHTML nested &lt;script&gt;</title>
</head>
<body>
  <script id="Product" type="text/html">
    <div class="product">
      ....
      <div class="features">
        <script id="Features" type="text/html">nested
          <div class="feature">
            ...
          </div>
        </script>
      </div>
      ...
    </div>
  </script>
</body>
</html>

Code snippet does not support XHTML, I have to use iframe with data URL:

<iframe src="data:application/xhtml+xml,%3Chtml%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%20contenteditable%3D%22true%22%3E%3Chead%3E%3Ctitle%3EXHTML%20nested%20%26lt%3Bscript%26gt%3B%3C%2Ftitle%3E%3C%2Fhead%3E%3Cbody%3E%3Cstyle%3Estyle%2C%20script%20%7B%20display%3A%20block%3B%20font-family%3A%20monospace%3B%20white-space%3A%20pre%3B%20padding-left%3A%2010px%20%7D%0Astyle%20%7B%20border-left%3A%2010px%20solid%20%2398A6C0%20%7D%0Ascript%20%7B%20border-left%3A%2010px%20solid%20%23D6F034%20%7D%3C%2Fstyle%3E%3Cscript%20id%3D%22Product%22%20type%3D%22text%2Fhtml%22%3Eouter%0A%20%20%20%20%3Cdiv%20class%3D%22product%22%3E%0A%20%20%20%20%20%20%20%20....%0A%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22features%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscript%20id%3D%22Features%22%20type%3D%22text%2Fhtml%22%3Einner%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22feature%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fscript%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20...%0A%20%20%20%20%3C%2Fdiv%3E%0A%3C%2Fscript%3E%3C%2Fbody%3E%3C%2Fhtml%3E" width="100%"></iframe>

Yes, it is possible to have nested <script> tags in HTML DOM:

productScript = document.createElement('script')
productScript.setAttribute('id', 'Product')
productScript.setAttribute('type', 'text/html')
productScript.appendChild(document.createTextNode('outer'))

product = document.createElement('div')
product.setAttribute('class', 'product')
product.appendChild(document.createTextNode(`
        ....
        `))

features = document.createElement('div')
features.setAttribute('class', 'features')

featuresScript = document.createElement('script')
featuresScript.setAttribute('id', 'Features')
featuresScript.setAttribute('type', 'text/html')
featuresScript.appendChild(document.createTextNode('inner'))

feature = document.createElement('div')
feature.setAttribute('class', 'feature')
feature.appendChild(document.createTextNode(`
        ...
    `))

featuresScript.appendChild(feature)
features.appendChild(featuresScript)
product.appendChild(document.createTextNode(`
        ...
    `))
product.appendChild(features)
productScript.appendChild(product)
document.body.appendChild(productScript)
script[type="text/html"] {
  display: block;
  font-family: monospace;
  white-space: pre;
  padding-left: 10px;
  border-left: 10px solid #D6F034
}

No, it is not possible to have nested <script> tags in HTML serialization. Its content is not parsed:

let product = document.getElementById('Product')
console.log(product.textContent)
<script id="Product" type="text/html">
    <div class="product">
        ....
        <div class="features">
            <script id="Features" type="text/html">nested
                <div class="feature">
                    ...
                </div>
            </script>
        </div>
        ...
    </div>
</script>

Comments

0

No, you can't really use the nested script tag inside . When it finds a similar tag inside, the browser will always stop building up the code execution. It does not matter if the nested script has an opening tag. It is because Browser doesn't parse the code as explained by TJ Crowder

Comments

-1

Try this:

<script id="Product" type="text/html">
<!--
    <div class="product">
        ....
        <div class="features">
            <script id="Features" type="text/html">
                <div class="feature">
                    ...
                </div>
            </script>
        </div>
        ...
    </div>
-->
</script>

When you need to get it:

document.getElementById("Product").text.replace(/(?:^\s*<!--\s*)|(?:\s*-->\s*$)/g, "");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.