Search code examples
javascriptcustom-element

The way to get full innerHTML in createdCallback while it has script tags


<script>
  var proto = Object.create(HTMLElement.prototype);
  proto.createdCallback = function() {
    this._innerHTML = this.innerHTML;
  }
  document.registerElement('template-mini', {
    prototype: proto
  })
</script>

<template-mini id='example1'>
  <script type='text/beforeUpdate'>
    console.log('hi')
    this.name = 'Bob'
  </script>
  <p>hello {{name}}</p>
</template-mini>

<template-mini id='example2'>
  <p>hello</p>
  <script type='text/beforeUpdate'>
    console.log('hi')
  </script>
</template-mini>

<script>
  console.log(example1._innerHTML)
  console.log(example2._innerHTML)
</script>

I'm developing a custom-element called template-mini https://github.com/zhoukekestar/webcomponents/tree/master/components/template-mini

When i use this template-mini, i need a preprocessor to modify data or add some function that can be used in template. So i have a script typed beforeUpdate, Unfortunately, i had the below issue:

https://bugs.chromium.org/p/chromium/issues/detail?id=502872

What should i do ? I want to get full innerHTML ( the script will be executed by my custom element ).


Solution

  • There are several solutions.

    1. If you can, wait for the document to be loaded before registering the <template-mini> custom element. Therefore you'll be sure that the content of the element is fully parsed when createdCallback() is called:

    document.addEventListener( 'DOMContentLoaded', function () {
        document.registerElement( 'template-mini', { prototype: proto } )
    } )
    

    2. Use another tag than <script>, for example <script-mini>. Anyway because of its specific type attribute it won't be interpreted as a normal script element.

    3. You can defer the time you'll get the content by using a function like setTimeout() or requestAnimationFrame():

    proto.createdCallback= function () {
        setTimeout( function ( e ) {
            e._innerHTML = e.innerHTML  
            console.log( e._innerHTML ) 
        }, 0, this )
    }        
    

    I'd recommend solution 2.