user6020072 user6020072 - 2 months ago 15
Javascript Question

How to execute a script when the custom element is upgraded

I have defined a custom element and I want to execute a script only when the custom element is upgraded to its registered type. The use case is that I must call a custom method.

My main html file looks like this:

<project-list></project-list>
<script>
var project_list = document.getElementsByTagName("project-list")[0]
project_list.custom_method("some_data");
</script>


The custom element is registered in a HTML import like this:

<script>
"use strict";
var currentScript = document._currentScript || document.currentScript;

class ProjectList extends HTMLElement {

createdCallback(){
console.log("created");
}

custom_method(data) {
console.log("custom_method() OK");
console.log(data);

this.innerHTML = data;
}

}

document.registerElement("project-list", ProjectList);
</script>


My question is simple: how to make sure the script in the main html file is called only after the custom element gains its
custom_method
method?


I'm looking for an elegant solution. Something that the spec authors would have thought of. I don't mind changing the architecture quite a bit (for example by moving the javascript from the main file into another custom element if that is necessary).

Answer

Sync HTML Import

As suggested by @dandavis, because of the sync default behaviour of the <link> and <script> elements, you just have to put your tags in the right order: registration before method call.

Or instead you can call your custom method when the DOMContentLoaded or the window.onload event is fired, as below:

window.onload = function() 
{
    var project_list = document.getElementsByTagName("project-list")[0]
    project_list.custom_method("some_data")     
}
<project-list></project-list>

<script>
  "use strict";
  var currentScript = document._currentScript || document.currentScript;

  class ProjectList extends HTMLElement {

    createdCallback(){
      console.log("created");
    }

    custom_method(data) {
      console.log("custom_method() OK");
      console.log(data);

      this.innerHTML = data;
    }

  }

  document.registerElement("project-list", ProjectList);
</script>

Async HTML Import

If for some reasons you want to load your HTML Import file asynchronousely, you can wait for the link.onload event. At this time the |<script> inside the import has been already exectued, the custom element registered and created.

<html>
<head>
  <title></title>
    <meta charset="utf-8" />
    <link rel="import" href="projectList.html" id="projectList" async>
    <script>
    projectList.onload = function ()
    {
      console.log( "import {loaded}" )
      var project_list = document.getElementsByTagName( "project-list" )[0]
      project_list.custom_method("some_data")
    } 
    </script>
</head>
<body>
    <project-list id="pl"></project-list>
    <script>
        console.warn( "custom_method is " + pl.custom_method ) //undefined
    </script>
</body>
</html>

With WebComponents.js polyfill

In this situation the polyfill won't instantiate the created object immediately after the import is loaded. Instead you should listen to the WebComponentsReady event:

document.addEventListener( "WebComponentsReady", function ()
{
    console.log( "WebComponentsReady" )
    var project_list = document.getElementsByTagName( "project-list" )[0]
    project_list.custom_method( "some_data" )
} )

It works with Firefox, IE 11, and also with Chrome.