1

I'm trying to integrate a Javascript library in my Polymer 1.7 element which uses document.getElementById(divId);. My Polymer element looks something like this:

<template>
  <div id="libDiv"></div>
  <button on-tap="go">Go!</button>
</template>
<script src="https://some-provider.com/greatlib.js"></script>
<script>
Polymer({
  is: 'lib-test',
  go: function () {
    GreatLib.render('libDiv');
  }
});
</script>

The library greatlib.js could look something like this:

var GreatLib = (function() {
  var render = function(divId) {
    document.getElementById(divId).innerHTML = 'GreatLib is great!';
  };
  return {render: render};
}());

Of cause document.getElementById(divId) can't find my div because it is in a Shadow DOM and not on the main document.

Is there a way to work around this and let document.getElementById(divId) find elements in my Polymer element, without modifying "GreatLib"?

Run the following example in Chrome:

<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<!--Use shadow DOM if available -->
<script>
  window.Polymer = {
    dom: 'shadow'
  };
</script>
<link href="polymer/polymer.html" rel="import">

<dom-module id="x-example">
  <style></style>
  <template>
  <div id="libDiv"></div>
  <button on-tap="go">Go!</button>
  </template>
  <script>
    var GreatLib = (function() {
      var writeTextToDiv = function(divId) {
        console.log('divId', divId);
        console.log('document.getElementById(divId)', document.getElementById(divId));
        document.getElementById(divId).innerHTML = 'GreatLib is great!';
      };
      return {
        writeTextToDiv: writeTextToDiv
      };
    }());
    
    Polymer({
      is: 'x-example',
      go: function () {
        GreatLib.writeTextToDiv('libDiv');
      }
    });
  </script>
</dom-module>

<x-example></x-example>
Svante
  • 1,069
  • 3
  • 12
  • 28
  • document.getElementById can access the shadow dom, if the element exists – gbro3n Jan 13 '17 at 10:30
  • I don't see how. ´document.getElementById(divId)´ returns null in this example. Got any example where this is not so? – Svante Jan 13 '17 at 11:51
  • maybe you call method before load page ? – Yigit Yuksel Jan 13 '17 at 11:59
  • @YiğitYüksel As you can see from the code, it is triggered with a button click. I can run it many times after load and get same results. – Svante Jan 13 '17 at 12:07
  • 2
    What makes you guys think that "document.getElementById(...)" works in Polymer elements? I have never seen anything info that indicated that, and it seems to be strongly indicated that it does not work if you read https://www.polymer-project.org/1.0/docs/devguide/local-dom – Svante Jan 13 '17 at 12:09
  • And this GreatLib has no way to accept a detached DOMNode ? Not so great IMO... – Kaiido Jan 13 '17 at 12:49
  • @Kaiido I wholeheartedly agree! But it is the interface given to us by our partner. – Svante Jan 13 '17 at 13:23
  • @Svante, so I gave you an hack has great as this lib ;-) Note that I really don't know Polymer, and that this hack should probably really not be used.. – Kaiido Jan 13 '17 at 13:26

1 Answers1

1

I don't know Polymer nor shadowDOM, and I took the opportunity of this question as an excuse to learn a bit on it.

So first of, it doesn't seem like a great idea to use ids for getting your shadowDOM. Also, as a reminder, shadowDOM is a way to hide the structure of your page.

But here is one Q/A that helped me to come to the conclusion that nope, document.getElementyId is not the right tool out-of-the box.

However, you can access it thanks to document.querySelector and the ::shadow selector so here is an horrible hack that should probably not be used by anyone but which seems to work :

(function(){
  // first check selector support
  try{
     document.querySelector('::shadow');
    }
  catch(e){
    return; // not supported don't change anything
    }
  var gbi = document.getElementById.bind(document);
  document.getElementById = function(_id){
    var el = gbi(_id); // first try the original one
    if(el){
      return el;
      }
    else // nothing, try in the shadow
      return document.querySelector('*::shadow #' + _id);
   }
  })()
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<!--Use shadow DOM if available -->
<script>
  window.Polymer = {
    dom: 'shadow'
  };
</script>
<link href="polymer/polymer.html" rel="import">

<dom-module id="x-example">
  <style></style>
  <template>
  <div id="libDiv"></div>
  <button on-tap="go">Go!</button>
  </template>
  <script>
    var GreatLib = (function() {
      var writeTextToDiv = function(divId) {
        console.log('divId', divId);
        console.log('document.getElementById(divId)', document.getElementById(divId));
        document.getElementById(divId).innerHTML = 'GreatLib is great!';
      };
      return {
        writeTextToDiv: writeTextToDiv
      };
    }());
    
    Polymer({
      is: 'x-example',
      go: function () {
        GreatLib.writeTextToDiv('libDiv');
      }
    });
  </script>
</dom-module>

<x-example></x-example>
Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285