Finding the shadowRoot from a script tag inside the shadowRoot?

288 views Asked by At

I am attempting to find a selector that is relative to the script that I have injected into the shadow dom.

I can find the element I need if I explicitly find it using the document, then selecting the shadowRoot and using querySelector again.

i.e. var selector = "document.querySelector('#shadow').shadowRoot.querySelector('img')";

Is it possible to get the shadowRoot without having to explicitly get the element that it is on from within the shadowRoot?

I have tried document.currentScript but it comes back as null when executed in the shadow dom

document.querySelector('#shadow').attachShadow({mode: 'open'}); 
var shadow = document.querySelector('#shadow');

shadow.shadowRoot.innerHTML =  '<img id="img"><div></div>';

var scriptElement = document.createElement('script');


// Can this be relative to the script tag?
var selector = "document.querySelector('#shadow').shadowRoot.querySelector('img')";

scriptElement.textContent = `

    JsBarcode(${selector}, "401246",
                    {
                        format: "CODE128",
                        displayValue: true,
                        height: 25,
                        width: 1,
                        fontSize: 16,
                        lineColor: "#000000"
                    }
                );
`;



var shadowDiv = document.querySelector('#shadow').shadowRoot.querySelector('div');

shadowDiv.appendChild(scriptElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsbarcode/3.11.5/JsBarcode.all.min.js"></script>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="src/style.css">
  </head>
  <body>
    <h1 id="header"></h1>

    <div id="shadow">
    
    </div>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jsbarcode/3.11.5/JsBarcode.all.min.js"></script>

    <script src="src/script.js"></script>
  </body>
</html>

1

There are 1 answers

0
Danny '365CSI' Engelman On BEST ANSWER

<script> run in Global scope, not in shadowRoot scope.

To prevent the 3rd party script loading multiple times.

  • load the <script> (in the <head> or anywhere)

  • use the script onload Event

    • (the Global JsBarCode Function is now defined)
    • then create a new Web Component <jsbar-code>
    • that encodes any existing or future <jsbar-code> tags
  • every <jsbar-code> calls the (Global!) JsBarCode function to transform its own <svg> in its shadowDOM

<jsbar-code value="210169"></jsbar-code>
<jsbar-code value="12312023" fontSize="21"></jsbar-code>
<jsbar-code format="upc" value="123456789012" textmargin="0" fontoptions="bold"></jsbar-code>
<jsbar-code format="pharmacode" lineColor="#0aa" width="4" height="40" value="21" displayValue="0"></jsbar-code>

<script>
  document.head.append(
    Object.assign(document.createElement("script"), {
      src: "//cdn.jsdelivr.net/npm/[email protected]/dist/JsBarcode.all.min.js",
      onload: () => {
        customElements.define(
          "jsbar-code",
          class extends HTMLElement {
            connectedCallback() {
              this.attachShadow({mode:"open"}).innerHTML = `<svg></svg>`;
              let attr = (x) => this.getAttribute(x) || "";
              let options = { // default options
                format: "CODE128",
                displayValue: attr("displayValue") != "0",
                height: 25,
                width: 1,
                fontSize: 16,
                lineColor: attr("lineColor") || "black"
              };
              Array.from(this.attributes).forEach(({
                nodeName, // override defaults with attribute settings
                nodeValue
              }) => options[nodeName] = nodeValue);
              // execute Global function
              JsBarcode(this.shadowRoot.querySelector("svg"), options.value, options);
            }
          }
        );
      }
    }))
</script>

Also available in JSFiddle Playground: https://jsfiddle.net/WebComponents/baeqszjm/