Polymer / polymer

Our original Web Component library.
https://polymer-library.polymer-project.org/
BSD 3-Clause "New" or "Revised" License
22.04k stars 2.01k forks source link

`ready` and property observers not fired until element is attached #4526

Closed valdrinkoshi closed 7 years ago

valdrinkoshi commented 7 years ago

In Polymer 2.x, ready and property observers are not fired until the element is attached http://jsbin.com/dahuve/1/edit?html,console,output

Polymer({
  is: 'x-sample',
  properties: {
    opened: {
      type: Boolean,
      value: false,
      observer: '_openedChanged'
    }
  },
  ready: function() {
    console.log('ready!');
  },
  attached: function() {
    console.log('attached!');
  },
  _openedChanged: function(opened) {
    console.log('_openedChanged: ' + opened);
    if (opened && !this.parentNode) {
      document.body.appendChild(this);
    }
  }
});

var el = document.createElement('x-sample');
el.opened = true; // does not trigger the observer!

Is this intended?

kevinpschaaf commented 7 years ago

Is this intended?

Yes.

This is one of the more significant breaking changes in 2.x, but our hand is forced by the V1 custom elements spec. Primary reason is that attributes are not available in constructor in V1 custom elements (they were in V0 custom elements), and we don't want to "boot" the element up until all initial data has been collected since it would be inefficient (significantly so for large trees). Connected is the best signal we have that all initial attributeChangedCallbacks have run. The Chrome web compoents team is investigating something like a "closeTagCallback" or a "parsingComplete" callback that would give us a better signal synchronous to e.g. cloneNode or createElement like we had in V0, but that's likely farther off.

justincy commented 7 years ago

attributes are not available in constructor in V1 custom elements

@kevinpschaaf Can you explain why that's the case? Is that a limitation of the v1 custom elements spec directly or of es6 classes? attributeChangedCallback can be called before an element is added to the DOM. I thought Polymer just added some sugar on top of that so I'm surprised by this limitation.

justincy commented 7 years ago

I found it: http://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance

The element must not gain any attributes or children, as this violates the expectations of consumers who use the createElement or createElementNS methods.

jfrazzano commented 7 years ago

I have to ask, because I have read those lines a few dozen times, and this line has always struck me as real bs. Who the heck is this consumer, and can I have a list of his/her other expectations? Is the consumer a browser? I don’t think its anyone who uses elements.

On Sep 11, 2017, at 6:12 PM, Justin notifications@github.com wrote:

I found it: http://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance http://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance The element must not gain any attributes or children, as this violates the expectations of consumers who use the createElement or createElementNS methods.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Polymer/polymer/issues/4526#issuecomment-328673801, or mute the thread https://github.com/notifications/unsubscribe-auth/AHxnvsukY6slAaLBftzhZfK5dgdKsRA4ks5shbBggaJpZM4M6371.

arthurevans commented 7 years ago

@jfrazzano Yes, in this case it would be people who use the elements.

Specifically, the idea is if I do:

let input = document.createElement('input');

I don't expect to get back an <input disabled> or an <input type="number">. I expect to get back a plain input element I can set up however I want. This expectation (that a newly-created element has no attributes) is built into the DOM spec.

https://dom.spec.whatwg.org/#concept-create-element

justincy commented 7 years ago

What a shame. My experience with this limitation is similar to that of the Basic Web Components developers. His solution was to rely on connectedCallback but that doesn't work when the element isn't going to be added to the DOM. Any recommendations on how to handle this?

arthurevans commented 7 years ago

@justincy That's a good question. I thought there was a method to force the element to ready itself, but I can't find it in the 2.x API docs, so maybe I'm confused.

In poking around at this issue, it appears to me that calling ready() on the element manually actually works—the element's shadow tree is created, properties set, and observers called. However, it seems hacky and might lead to side-effects if you subsequently added the element to the DOM. Perhaps @kevinpschaaf can enlighten us here.

Out of curiosity, what's the use case you're trying to solve with an element that's not connected to the DOM (as opposed to a plain JS object, for example). Are you trying to get it ready before you attach it to the DOM? Or does it remain detached?

justincy commented 7 years ago

@arthurevans I'm trying to allow an element to be useful whether or not it's attached to the DOM. My specific usecase is similar to how iron-ajax uses iron-request. My element represents an API request. In most cases it would be used in shadow DOM but I also want the option of using it in class mixins or in a scenario where the number of requests aren't known in advance.

I wanted to use shadow DOM within this request element for a dependency on another custom element that connects it to an SDK client and I wanted property observers so that I could do something similar to iron-ajax's auto behavior. In this request element and it's dependency, I guess I can get along without shadow DOM, bindings, and observers but then I might as well not be using Polymer.