Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

Delayed createdCallback #4

Closed
einarq opened this issue Aug 15, 2014 · 18 comments
Closed

Delayed createdCallback #4

einarq opened this issue Aug 15, 2014 · 18 comments

Comments

@einarq
Copy link

einarq commented Aug 15, 2014

Sorry if this is a non-issue, custom elements and this excellent polyfill is quite new (and exciting) to me.

I'm trying to use this in a Backbone app, where each view has its own template, and that template might contain some custom element (the view then also makes sure that the custom element is registered first).

I noticed that when I insert the template with the custom element in the dom, there is a slight delay before the createdCallback even exists on the custom element and I can communicate with the properties of the custom element.
This does not happen in Chrome where registerElement is natively supported. It also happens when using the polyfill from Polymer though.

Any idea why this happens? This makes it a bit harder to work with, and the difference between the native version and the polyfill is a bit worrisome.

Here is a test case:
http://jsfiddle.net/mt06sykv/

Thanks in advance for any reply.

Einar

@goldoraf
Copy link

Custom elements upgrade is async, therefore if you query a node before it had the chance to upgrade, you will not be able to access its properties. That's why a 'WebComponentsReady' event is needed.

@einarq
Copy link
Author

einarq commented Aug 15, 2014

But still a bit weird that it doesnt happen when using the native version in Chrome though, right? Shouldn't the polyfill aim to be as close to the native version as possible? Or is Chrome actually misbehaving by not having a slight delay?

@goldoraf
Copy link

Native impl. can upgrade elements as soon as they appear, the polyfill must use mutation observers, which are async and add the slight delay. This is a normal limitation of the polyfill.

@einarq
Copy link
Author

einarq commented Aug 15, 2014

Ok, thanks

@einarq einarq closed this as completed Aug 15, 2014
@WebReflection
Copy link
Owner

without a demo page it's hard to understand if the issue comes from MutationObserver laziness, as @goldoraf mentioned, or it's caused by this line which should theoretically use setImmediate instead but unfortunately only IE implemented such method.

Here the quick summary of the reason it's async.

The moment you define a constructor or generally speaking a custom element the polyfill needs to grab all nodes in the DOM that already fulfill the description.

This must be done asynchronously because otherwise you might end up in a situation where you don't have any reference to such constructor … example:

<!-- not registered yet -->
<x-e>must be initialized async</x-e>
<script>
// imagine I have removed that setTimeout
var XE = document.registerElement(
  'x-e',
  {
    prototype: Object.create(
      HTMLElement.prototype, {
      createdCallback: {value: function() {
        // will be undefined because
        // XE hasn't been assigned yet
        alert(this.constructor === XE);
      }}
    })
  }
);

// now if we do this instead
document.body.appendChild(
  document.createElement('x-e')
);
// now it alerted `true` instead
</script>

Please feel free to ask me more, if necessary, and apologies I could not give you exact same native implementation.

@einarq
Copy link
Author

einarq commented Aug 17, 2014

Not sure what you mean by no demo page, I included a jsfiddle in the github
issue. But I understand the reasons for needing to be async, and I agree
that having some sort of custom event that is not in the spec probably
isn't the best approach. I'll just have to work around it some how, just a
shame that there is a difference between the native implementation and the
polyfill. Great stuff anyway though!

Thanks

On Fri, Aug 15, 2014 at 1:14 PM, Andrea Giammarchi <notifications@github.com

wrote:

without a demo page it's hard to understand if the issue comes from
MutationObserver laziness, as @goldoraf https://github.com/goldoraf
mentioned, or it's caused by this line
https://github.com/WebReflection/document-register-element/blob/master/build/document-register-element.max.js#L478
which should theoretically use setImmediate instead but unfortunately
only IE implemented such method.

Here the quick summary of the reason it's async.

The moment you define a constructor or generally speaking a custom element
the polyfill needs to grab all nodes in the DOM that already fulfill the
description.

This must be done asynchronously because otherwise you might end up in a
situation where you don't have any reference to such constructor … example:

must be initialized async<script>// imagine I have removed that setTiemoutvar XE = document.registerElement(
'x-e',
{
prototype: Object.create(
HTMLElement.prototype, {
createdCallback: {value: function() {
// will be undefined because
// XE hasn't been assigned yet
alert(this.constructor === XE);
}}
})
});
// now if we do this insteaddocument.body.appendChild(
document.createElement('x-e'));// now it alerted true instead</script>

Please feel free to ask me more, if necessary, and apologies I could not
give you exact same native implementation.


Reply to this email directly or view it on GitHub
#4 (comment)
.

@RangerMauve
Copy link

Why not have the createdCallback emit an event in backbone instead of having backbone look for the element?

@WebReflection
Copy link
Owner

Sorry @einarq, I actually didn't notice the link and it's probably not working on Safari … but funny enough, I've realized that Chrome fails big time with the check I've bothered to solve … the constructor is there, but it's outer scope assignment is undefined.

I'll have a look if I can actually do the same without breaking everything but this feels wrong, invoking through a definition that is not yet available, feels a bug in Chrome, rather than something I should fix here.

Stay tuned!

@RangerMauve that's what I've suggested in the other thread too:

// before loading custom element
document.addEventListener(
  'my-custom-elem:created',
  function (e) {
    var node = e.detail;
    // do stuff
  }
);

// from the Custom Element
createdCallback: function () {
  document.dispatchEvent(
    new CustomEvent(
      this.nodeName.toLowerCase() + ':created',
      {detail: this}
    )
  );
}

@einarq
Copy link
Author

einarq commented Aug 17, 2014

Do you need to worry about Chrome at all when it actually supports registerElement?

@RangerMauve, yes that is a possible workaround, but I'm trying to keep the custom element as clean as possible, not needing to know about things like Backbone or jQuery. Will make it possible to use in non-Backbone apps as well.
I like the proposed dispatchEvent solution though.

Thanks

@WebReflection
Copy link
Owner

Do you need to worry about Chrome at all when it actually supports registerElement?

as Web developer is my duty to file bugs or to do same thing native does … I actually would like to understand if that's a meant/OK behavior 'cause if not they should fix it, and you won't have eny difference between this polyfill and native, otherwise I might fix it and bring you closer to native like expectations.

@einarq
Copy link
Author

einarq commented Aug 17, 2014

Agree, probably didn't quite understand the problem.

@WebReflection
Copy link
Owner

described here: https://code.google.com/p/chromium/issues/detail?id=404466
will track and if there's some plot twist in there, will drop the setTimeout in here

@einarq
Copy link
Author

einarq commented Aug 17, 2014

And of course the CustomElement constructor doesnt work in IE 10 (havent checked 11), so I guess I'll just go with a Backbone event.

Thanks

@WebReflection
Copy link
Owner

naaaaa, don't do that, simply bring DOM4 awesomeness in IE10, 9, and 8 too if needed.
Let me introduceyou DOM4, it lets you forget about libraries:
https://github.com/WebReflection/dom4#dom4

@WebReflection
Copy link
Owner

Can anyone please check 0.1.0 and tell me if there is any improvement ?

I've talked with Chromium guys and they told me I could happily remove that setTimeout.

Thanks

@einarq
Copy link
Author

einarq commented Aug 25, 2014

I tried using the latest version from the build folder, but it seems the
behavior is still the same. Check the log in FF:
http://jsfiddle.net/mt06sykv/3/

On Thu, Aug 21, 2014 at 11:49 PM, Andrea Giammarchi <
notifications@github.com> wrote:

Can anyone please check 0.1.0 and tell me if there is any improvement ?

I've talked with Chromium guys and they told me I could happily remove
that setTimeout.

Thanks


Reply to this email directly or view it on GitHub
#4 (comment)
.

@WebReflection
Copy link
Owner

In that case I'm afraid the mutation event might be responsible and there's not much I can do, or better, I am not planning to overwrite innerHTML and intercept in there registered elements 'cause that would cause thousand other problems :-(

Hope you can live with current behavior

@WebReflection
Copy link
Owner

this has been resolved through a possible work-around described here:
#15 (comment)

TL;DR whenver you need synchronous behavior after DOM manipulation, simply trigger a readystatechange event, the poly will take care of everything else.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants