Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

defined promise #427

Closed
jakearchibald opened this issue Mar 9, 2016 · 14 comments
Closed

defined promise #427

jakearchibald opened this issue Mar 9, 2016 · 14 comments

Comments

@jakearchibald
Copy link

Following from #425.

The :defined pseudo allows basic styling before an element becomes defined, such as reserving space for the element. However, that isn't always sufficient, and it feels like an extensible web violation to be able to react to upgrades via CSS but not via script.

A property that resolves once an element is defined is a more extensible system. Could/should this be a static property on the class? (edit: lol no)

I don't want my element to be defined ahead of elements it uses in its shadow

Promise.all(
  [
    'x-foo',
    'x-bar',
    'x-whatever'
  ].map(tagName => document.whenDefined(tagName))
).then(() => {
  document.defineElement('my-element', MyElement);
});

I don't want to show an article until all custom elements have defined

fetch(articleURL).then(r => r.text()).then(text => {
  articleContainer.innerHTML = text;
  return Promise.all(
    [...articleContainer.querySelectorAll(':not(:defined)')]
      .map(el => document.whenDefined(el.tagName))
  );
}).then(showArticle);
@treshugart
Copy link

FWIW we've done something similar in Skate. The major use-case for us being that custom element upgrading can be erratic depending on when definitions are loaded and when the parser encounters them (elaborate explanation in the link). If you have a parent that needs to interact with a child, then you need a way to know when the child is upgraded.

The other major use-case is what @jakearchibald mentioned which seems a result of :defined only working for the selected custom element. It won't work in scenarios where you want to ensure its descendants are :defined prior to showing the ancestor (correct me if I am wrong).

@domenic
Copy link
Collaborator

domenic commented Mar 10, 2016

Could/should this be a static property on the class?

I don't think this is a good idea since we shouldn't modify author-defined classes. It also doesn't make terribly much sense; if you have the class present, then you've probably already registered it. E.g. in your second example el.constructor will only be the custom element constructor after upgrade has already happened.

If I were to pick an API shape for this it'd be document.whenDefined('x-mytag').

@jarek-foksa
Copy link

document.whenDefined("x-mytag") is not very descriptive, I would suggest document.whenElementDefined("x-mytag") or something that mimics document.fonts.* APIs which also return promises.

@rniwa
Copy link
Collaborator

rniwa commented Mar 10, 2016

I'd prefer having customElements attribute on document or window instead of adding a bunch of methods on document as in:

document.customElements.define('my-element', MyElement);
document.customElements.check('my-element').then(~);

@domenic
Copy link
Collaborator

domenic commented Mar 10, 2016

If we're going to do that, we should do it soon. It would also be a good place to potentially stuff my document.upgradeElement from #419 (comment) if we do want to expose that primitive.

An alternative is statics on HTMLElement. That might match reality better since these are not very document-scoped after all, as we discovered in #369.

@jakearchibald
Copy link
Author

It also doesn't make terribly much sense; if you have the class present, then you've probably already registered it

I started with a property on the instance (like :defined), but found myself needlessly creating elements just to monitor their definition. So yeah, your proposal works.

Really not sure what I was thinking, putting the property on classes that clearly won't exist yet :/

This was referenced Mar 11, 2016
@domenic
Copy link
Collaborator

domenic commented Apr 8, 2016

So, this is pretty easy to add spec-wise. What is the implementer interest? @rniwa seemed vaguely supportive in #427 (comment) but I'd love to hear more of his opinion. @annevk, could you ask Gecko folks? @esprehn @kojiishi, any thoughts from Blink? @travisleithead, any thoughts from Edge?

@rniwa
Copy link
Collaborator

rniwa commented Apr 8, 2016

yeah, we think most components would like to wait for their dependencies to come in before instantiating/initializing themselves so having some feature to detect that seems useful.

In terms of implementation, this is pretty trivial to implement unless I'm missing something.

@annevk
Copy link
Collaborator

annevk commented Apr 9, 2016

I think Mozilla is fine with this. Paging @smaug---- and @inscriber just in case.

@smaug----
Copy link

Not sure what the actual proposal is here, but sounds useful.
So, would it be document.whenDefined("x-mytag") returning a Promise, or could that
method take an array of tag names? document.whenDefined(["x-mytag1", "x-mytag2"]) ?

Do we need to think about shadow dom here? I guess no, custom elements registry is currently global, which may not be quite right. (thinking about some closed shadow dom wanting to use some specific custom element but not expose that to outer world.) But that is a separate issue.

@domenic
Copy link
Collaborator

domenic commented Apr 9, 2016

So, would it be document.whenDefined("x-mytag") returning a Promise

Just that one; to check multiple at once you use Promise.all([document.whenDefined("x-mytag1"), document.whenDefined("x-mytag2")]).

I guess no, custom elements registry is currently global, which may not be quite right. (thinking about some closed shadow dom wanting to use some specific custom element but not expose that to outer world.) But that is a separate issue.

Hmm, that's a pretty interesting point (although I agree it's separate). People have talked about a registries API (#154 and elsewhere) but I hadn't considered if closed shadow roots give us new flexibility in that area.

I guess we still have the problem that motivated us to make the registry per-global instead of per-document in the first place, which is that there's only one HTMLElement constructor per global, so when authors do new MyXTag() which does super() calling HTMLElement, there's no way to know which registry to look up the element in.

@kojiishi
Copy link

It looks useful to me too. @hayatoito

@hayatoito
Copy link
Contributor

I think Blink is fine with this.

domenic added a commit to whatwg/html that referenced this issue Apr 13, 2016
As discussed in WICG/webcomponents#427, this
adds the ability for authors to wait for a given custom element name to
become defined.
@domenic
Copy link
Collaborator

domenic commented Apr 13, 2016

This has been specced in whatwg/html#1047 in case people want to review.

domenic added a commit to whatwg/html that referenced this issue Apr 14, 2016
As discussed in WICG/webcomponents#427, this
adds the ability for authors to wait for a given custom element name to
become defined.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants