Polymer: How to extend PolymerElements?

Created on 14 Jun 2017  路  5Comments  路  Source: Polymer/polymer

I'm trying to extend app-drawer following the instructions here #4556
Having this code I'm getting the following error in chrome. Other browsers not tested.

customElements.whenDefined('app-drawer').then(() => {
            class MobileLeftMenu extends customElements.get("app-drawer") {
                static get is() {
                    return 'mobile-left-menu'
                }
            }
            customElements.define(MobileLeftMenu.is, MobileLeftMenu);
})

error:

app-drawer.html:514 Uncaught TypeError: Cannot read property 'style' of undefined
    at HTMLElement._styleTransitionDuration (app-drawer.html:514)
    at Object.runMethodEffect [as fn] (property-effects.html:771)
    at runEffectsForProperty (property-effects.html:137)
    at runEffects (property-effects.html:103)
    at HTMLElement._propertiesChanged (property-effects.html:1564)
    at HTMLElement._flushProperties (property-accessors.html:512)
    at HTMLElement.ready (property-effects.html:1522)
    at HTMLElement.ready (element-mixin.html:654)
    at HTMLElement.ready (legacy-element-mixin.html:151)
    at HTMLElement.ready (class.html:205)

Is it possible to extend PolymerElements at all? No documentation found

2.x needs investigation p1

Most helpful comment

Extending other elements and modifying templates is a topic that probably needs a bit more exploration and documentation for good patterns.

All 5 comments

You can. There are some docs here:

https://www.polymer-project.org/2.0/docs/devguide/custom-elements#extending-other-elements
https://www.polymer-project.org/2.0/docs/devguide/dom-template#inherited-templates

I can't reproduce your error with the code you showed above, but if I add a new <dom-module> with a template for this element, I get the error.

So it looks like you're replacing the template of the parent element. If you want to insert content into the parent element template, see the second link above. You can also use composition (create a parent element that includes an app-drawer with some contents).

One catch with extending an element and manipulating its template is that you need to know which internal elements the parent element references (for example, in this case, the app-drawer code is trying to access this.$.contentContainer, but that element doesn't exist in the new template).

Extending other elements and modifying templates is a topic that probably needs a bit more exploration and documentation for good patterns.

Two safe patterns you can use when subclassing and modifying a template are:

  1. clone the super class template and wrap it with additional DOM (e.g. insert the parent template into a new template)
  2. clone the super class template and insert additional DOM into it

Creating a new template for the subclass from whole cloth is more risky because as @arthurevans pointed out Polymer elements may reference specific nodes from the template in imperative code (typically nodes with id via the this.$ map), so you need to maintain that id-node contract in the sub template, or else override the methods with those references. This is less of an issue when elements only modify their templates via data-binding, since the links to the template via the data-binding are re-evaluated with each new template.

Here is an example of how to extend element and also cloning the template and being able to use own