Polymer: Polymer 2.0 API may add stutter, or increase learning curve

Created on 29 Sep 2016  ·  23Comments  ·  Source: Polymer/polymer

Wohoo! Congrats! Looking forward to seeing how 2.0 pans out!
The gist of this feedback is that IMHO the 2.0 class-based definition adds stutter to a very clean API, albeit at a few advantages.

I know Polymer 2.0 will have a compatibility layer for the old factory method, but I think the old factory method should be kept as the recommended element creation method. IMHO, it makes it much easier to grok an element's functionality at a glance--and I promise I'm not saying this because I've been staring at those for a while now.

Supporting arguments based on visual guide on migrating.

  • Extending/subclassing MyElement from multiple behaviors will now either require a really long line, or a line that's broken and has to then be closed with many parentheses, whereas before we just used an array of class-like objects.
  • static get is() { return 'my-element'; } repeats the element's class name and is much longer than just is: 'my-element': Keeping the factory-like Polymer() helper would allow the class to be dynamically created, would be shorter, and would not require two versions of the MyElement name.
  • static get config() { return ...} similar argument to that of is, except that it also takes observers, but not listeners. The map-style API we had with observers and listeners was really terse and really easy to understand. Removing listeners from here breaks that terseness and adds a bit of complexity.
  • customElements.define is another piece of boilerplate that seems ripe for extracting into a factory method.

In short, I think you could (and should) hide the fact that you're creating a class in a factory method, and keep the clean API we already have. Yes, classes are convenient, but I think in this case, they are getting in the way of keeping the API clean.

2.x api-feedback

Most helpful comment

I have to disagree, the legacy method for constructing elements is far from what Polymer aims to be: a web component base/library.

How do you define a web component?

class MyElement extends HTMLElement { }

As you can see, Polymer 2.x stays very close to this (extends Polymer.Element), as it should.

Your arguments against such a class are the reason Polymer 1.x was so far from how a normal web component looks. We shouldn't be aiming to make your code shorter but rather to provide a base element to inherit rather than HTMLElement. In 2.x, what you see is what gets defined as a custom element, rather than being a configuration object which internally produced such a definition (1.x) hidden away from you.

All 23 comments

I have to disagree, the legacy method for constructing elements is far from what Polymer aims to be: a web component base/library.

How do you define a web component?

class MyElement extends HTMLElement { }

As you can see, Polymer 2.x stays very close to this (extends Polymer.Element), as it should.

Your arguments against such a class are the reason Polymer 1.x was so far from how a normal web component looks. We shouldn't be aiming to make your code shorter but rather to provide a base element to inherit rather than HTMLElement. In 2.x, what you see is what gets defined as a custom element, rather than being a configuration object which internally produced such a definition (1.x) hidden away from you.

Yup, you're right... Polymer tries to be a thin layer above on top of the native API, and since the existing API isn't that complicated (extends HTMLElement), there's no need to complicate things or obfuscate them by adding a layer/factory method. You've convinced me that keeping that base class style is an okay idea, and I concede.

Keeping code short and easy to parse for the human brain should still be at the top of the priorities though. So how about the following amendment to my initial ideas?

  • Is there a way to avoid setting is? It seems to duplicate the MyElement name. Maybe something like this?
class Polymer.Element { 
  static get is() {
    return this.name.replace(/\B[A-Z]([A-Z])*/g, '-$&').toLowerCase()
  }
}
  • Making properties and observers part of the metadata/config but not listeners and hostAttributes, seems a bit arbitrary and adds to the learning curve. How about either moving properties and observers out into their own static getters, or moving listeners and hostAttributes into the config?

The “how do you define a web component?” question, on a more abstract level, is the one that we have been debating/dealing with.

In the simplest, non-extended, component compositions, imagine just having an input element, in a repeater, with a bind to its “type” property, class and value passing properties; i.e:


In this collection pseudo-form pages, what is the element? What is the component? What is the class that we apply? At the “element-level”, the input-element could be a check-box, a number input, a radio-button, a date-time, a search, or even —with a little more sugar(as we implemented)—a searchable, animated input with a animated dropdown menu of search options based on the property being inputted.

What constitutes the component “class” or type of the inner template’s page?

Is it a set of 8 inputs with dropdowns? (A common implementation for us.)

Is it a one page check box form?

What “elements” will be there? Who will know?

In our implementation, we had no idea ahead of time. Whatever prototypes of users, work-schedules, questions, calendars, or events, w/e were being used in the “input interface”, we just sliced up the properties on the proto constructor and--based on data-structure and property names with specific uses of underscores and camel case—automatically created labels, local property names, and baskets of property names to fill value objects handled in our multi-page pseudo-forms.

This model, which was hyper fast, extremely portable, low-overhead, and super re-usable seems beyond, at least our ability, to recreate in new polymer or the v1 spec.

For example, how do we define the class and its attributes without factories, or the ability to talk to child elements prior to load?

How, in any of these instances, do we even begin to answer the question What is the “component”?

If the above is laid-out as follows: