alonisser
alonisser

Reputation: 12098

failing to populate shadow DOM (following tutorial)

I'm playing the the Shadow DOM 101 tutorial at html5rocks. I'm using Chrome 25.0.1364.172 and when I try to appendChild to the Shadow DOM root (as shown in the tutorial) I get an Uncaught Error: NotFoundError: DOM Exception 8. I guess I'm missing something obvious but I can't figure out what. Here's the code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Test the shadow dom</title>

    </head>
    <body>
        <div id="myName">Alon</div>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
        <script id="myNameTemplate" type="text/x-tmpl-template">
            <style>
                .outer {
                    border:2px solid brown;
                    border-radius: 1em;
                    background: red;
                    font-size: 28pt;
                    width: 12em;
                    height:2em;
                    text-align: center;
                }
                .boilerplate {
                    color:white;
                    font-family: sans-serif;
                    padding:0.5em;
                }
                .name {
                    color:black;
                    background: white;
                    font-family: "Marker Felt", cursive;
                    font-size: 45pt;
                    padding-top:0.2em;
                }
            </style>
            <div class="outer">
                <div class="boilerplate">
                    Hi! my name is
                </div>
                <div class="name">
                    alon
                </div>
            </div>
        </script>
        <script>
            $(document).ready(function(){
                var shadow = document.querySelector("#myName").webkitCreateShadowRoot();
                console.log(shadow);// I get #shadow-root in the console
                var template = $("#myNameTemplate").html();//also tried text(), without jQuery with innerHTML and other options
                console.log(template);//I get the content of the template in the console
                shadow.appendChild(template); //this part breaks
             });
        </script>
    </body>
</html>

Since my browser doesn't support the new <template> tag shown in the tutorial I changed it to <script type="text/x-tmpl">.

Edit: I get the same error from the console when I try:

shadow.appendChild('<div></div>')
Error: NotFoundError: DOM Exception 8

Upvotes: 0

Views: 493

Answers (2)

Chris Rymer
Chris Rymer

Reputation: 713

You have got some of the markup wrong and a few lines in the script that select the template are incorrect. I have modified the code so it works.

<script id="myNameTemplate" type="text/x-tmpl-template">
...
</script>

to this

<template id="myNameTemplate">
...
</template>

And in your script at the bottom of the page I modified your template var, it was using jQuery for some reason and not querySelector(). So this code below

$(document).ready(function(){
    var shadow = document.querySelector("#myName").webkitCreateShadowRoot();
    console.log(shadow);// I get #shadow-root in the console
    var template = $("#myNameTemplate").html();//also tried text(), without jQuery with innerHTML and other options
    console.log(template);//I get the content of the template in the console
    shadow.appendChild(template); //this part breaks
});

becomes this

$(document).ready(function(){
    var shadow = document.querySelector("#myName").webkitCreateShadowRoot();
    var template = document.querySelector("#myNameTemplate");
    shadow.appendChild(template.content);
});

Here is the complete markup

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Test the shadow dom</title>

</head>
<body>
    <div id="myName">Alon</div>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <template id="myNameTemplate">
        <style>
            .outer {
                border:2px solid brown;
                border-radius: 1em;
                background: red;
                font-size: 28pt;
                width: 12em;
                height:2em;
                text-align: center;
            }
            .boilerplate {
                color:white;
                font-family: sans-serif;
                padding:0.5em;
            }
            .name {
                color:black;
                background: white;
                font-family: "Marker Felt", cursive;
                font-size: 45pt;
                padding-top:0.2em;
            }
        </style>
        <div class="outer">
            <div class="boilerplate">
                Hi! my name is
            </div>
            <div class="name">
                alon
            </div>
        </div>
    </template>
    <script>
        $(document).ready(function(){
            var shadow = document.querySelector("#myName").webkitCreateShadowRoot();
            console.log(shadow);// I get #shadow-root in the console
            var template = document.querySelector("#myNameTemplate");//also tried text(), without jQuery with innerHTML and other options
            console.log(template);//I get the content of the template in the console
            shadow.appendChild(template.content); //this part breaks
         });
    </script>
</body>

You cannot use anything other than the .content of the template AFAIK because template is a Document Fragment and to access that fragment you are required to select the inner content of the HTML5 element <template>.

The way I look at it is that the <template> tag is basically a static HTML way of creating a document fragment that you can grab with the javascript method querySelector(). You could create the fragment using createDocumentFragment() if you wanted to append the DOM through an extension or whatever but that's another bucket of frogs.

Upvotes: 0

dfreedm
dfreedm

Reputation: 76

appendChild() has never worked like that

document.body.appendChild('<div></div>') will give you the same error.

What you want is shadow.innerHTML = template;

Upvotes: 3

Related Questions