-1

(originally from https://github.com/w3c/webcomponents/issues/392, moved here)

I'm working on a library (at http://infamous.io, for now at least) in which I'm creating a set of Custom Elements for rendering a 3D scene. The library registers two elements, [<motor-scene>](https://github.com/infamous/infamous/blob/master/src/motor-html/scene.js) and <motor-node>. The library depends on this document.registerElement polyfill for non-supporting browsers.

I have a small problem. Everything works fine when I use the custom elements in the <body> of a Meteor app, but when I try doing the exact same thing with a static HTML page and the scripts manually included in the <head>, it fails and doesn't work as expected. I'm not sure if I'm doing something wrong and don't know something about Custom Elements, or if there's a problem with the API.

To see the working demo, just

git clone git@github.com:trusktr/site.git
cd site
git checkout infamous-motor-html # it's on this branch.
npm install
meteor # meteor is really easy to install, meteor.com
# visit localhost:3000

The result looks like this, the teal and pink elements positioned as expected in 3D space:

working

Now, if you look in the public folder, you'll see the static version in html-demo.html. You can open this directly in your browser with file://, or visit localhost:3000/html-demo.html while running the Meteor app. I have double checked, and I believe that I am doing the same exact thing as in the Meteor version, but I simply cannot get the expected result, and it looks like this:

not-working

I'm not sure what the problem is, and why it works in the Meteor version (Meteor 1.3 compiles the code with Babel) and doesn't work in the static version (also compiled with Babel via Webpack).

I've added console.logs to the createdCallback, attachedCallback, etc methods in the registerElement calls (for example). This shows two different orderings of output in the console.

The output for the Meteor version:

meteor-output

The output for the static version:

static-output

Could there be a load-order problem? Are there any rules on when registerElement should be called? I tried placing the static scripts at the end of the page, which changes the output order, but still renders the same thing (broken, not like the Meteor version).

Any ideas? Is there something about Custom Elements that I don't know? Why does the static example not appear the same as the Meteor example?

Note: I get the same inconsistent behavior between Meteor and static, when using the WebReflection/document-register-element polyfill, and when not.

trusktr
  • 44,284
  • 53
  • 191
  • 263
  • Please add the information you placed in the GitHub issue here. They may very well delete that issue, and then this question would not make any sense. – Heretic Monkey Feb 22 '16 at 21:27
  • @MikeMcCaughan Thanks. Updated. – trusktr Feb 22 '16 at 21:46
  • I don't understand your question. Custom Elements work in static pages. In your logs, I can seen that Custom Elements are registered and created so the issue is not related to `registerElement`. You sould try with a simple example. – Supersharp Feb 23 '16 at 08:06
  • @Supersharp I guess they do, but something is different. In Meteor Blaze, the components are added to the page later, dynamically. In the static one, the components exist in the markup when the page is fetched and before the HTML markup is parsed. Perhaps something is happening asynchronously somewhere that I'm racing against, and I haven't found what that is yet. – trusktr Feb 28 '16 at 09:04

1 Answers1

0

If indeed your problem is a race condition between elements being created, then your element may wait until all the other elements it depends upon are created/attached.

Then it won't matter the load-order, and you will be able to place your scripts anywhere.

See my answer here: How to execute a script when the custom element is upgraded

Community
  • 1
  • 1
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
  • Thanks@MarcG! In that answer you linked, you use ES6 Class syntax to define your custom elements. How does that work? I thought `document.registerElement` accepts only a name and a prototype, not a class constructor? – trusktr Mar 07 '16 at 00:25
  • 1
    If `CustomX` is your class: `document.registerElement("custom-x", CustomX);` – Marcelo Glasberg Mar 07 '16 at 01:25
  • Interesting, it works in Chrome with experimental JavaScript enabled (so not ready for production, unless it also works with ES5 constructor pattern). The class `constructor() {}` doesn't get fired though; the browser bypasses that somehow. In my test, it fired the `createdCallback` without firing the `constructor`. The documentation I've found so far shows the method of providing an options object with a `prototype`, and I also read somewhere that classes aren't supported due to how `document.registerElement` works, which is obviously not true anymore. Where is this documented? – trusktr Mar 07 '16 at 17:54
  • It also appears that `document.registerElement` returns a new constructor which we need to use if we want to make new instances. I assume we can't use our original class constructor? EDIT: Interesting, when I try to use the class directly as in `document.body.appendChild(new CustomX())`, Chrome throws `Uncaught ReferenceError: this is not defined` and the error points to the line with the constructor definition. I ended up using this pattern: http://trusktr.io:7777/eqogedadol.js – trusktr Mar 07 '16 at 18:00
  • Updated the snippet, we can actually re-assign to the same CustomX identifier, so it's like a higher-order component: http://trusktr.io:7777/ijirusogud – trusktr Mar 07 '16 at 18:06
  • Sweeeeeeeeeeeeeeeeet. I just tested, it works with ES5 constructor functions too, no flags necessary. Where'd you find out about this? – trusktr Mar 07 '16 at 18:20
  • Oh, duuuuuh!!! The `options` parameter has to have the `prototype` property, so, obviously, if we pass a constructor function via the `options` parameter then it will work since the function will have a `prototype` property! Doh!!! – trusktr Mar 07 '16 at 19:17
  • 1
    @trusktr In any case, did you solve your original problem? – Marcelo Glasberg Mar 08 '16 at 20:58
  • Yes indeed I did. :] – trusktr Mar 17 '16 at 20:28