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

Polymer "inheritance" proposal - expose more mixins!! #2510

Closed
ebidel opened this issue Sep 30, 2015 · 8 comments
Closed

Polymer "inheritance" proposal - expose more mixins!! #2510

ebidel opened this issue Sep 30, 2015 · 8 comments

Comments

@ebidel
Copy link
Contributor

ebidel commented Sep 30, 2015

From @kristianmandrup on September 30, 2015 7:45

I fully understand why you wen't away from full components inheritance. A crude weapon indeed.
However it would be VERY convenient if all elements exposed their style, properties and behaviour as mixins for other elements to build on.

This IS currently possible, so it is only a matter of enhancing existing elements to follow this pattern to allow for better composition.

This would also help to solve the "problem" with the content selector limitation: googlearchive/core-selector#39

Example paper-scroll-header-panel

var mixinElement = Polymer.registry('paper-scroll-header-panel')

Polymer.extend({
  properties: [
    mixinElement.properties, 
    AnotherSetOfproperties, 
  ],
  behaviors: [
    myOtherMixinElement.behaviors,
    someNiceBehavior,
    mixinElement.behaviors
  ]
}, {
  // my specific element overrides and customizations
});

You could of course see a behavior as a full set of properties and methods which form a logical unit. Then expose methods and properties as separate mixin units as well. Then allow full inheritance as a convenience, which simply inherits all behaviors and the shared styles exposed by the elements as well.
Provide full flexibility and granular control.

Cheers!

Copied from original issue: googlearchive/polymer-patterns#46

@ebidel
Copy link
Contributor Author

ebidel commented Sep 30, 2015

From @kristianmandrup on September 30, 2015 13:44

After some research into polymer core I see the following methods are already available, however not really documented very well. I guess they could be used as a starting point?

Polymer.Base

     * @method extend
     * @param {Object} prototype Target object to copy properties to.
     * @param {Object} api Source object to copy properties from.
     * @return {Object} prototype object that was passed as first argument.
     */
    extend: function(prototype, api) {

    /**
     * Copies props from a source object to a target object.
     *
     * Note, this method uses a simple `for...in` strategy for enumerating
     * properties.  To ensure only `ownProperties` are copied from source
     * to target and that accessor implementations are copied, use `extend`.
     *
     * @method mixin
     * @param {Object} target Target object to copy properties to.
     * @param {Object} source Source object to copy properties from.
     * @return {Object} Target object that was passed as first argument.
     */
    mixin: function(target, source) {
      for (var i in source) {
        target[i] = source[i];
      }
      return target;
    },

    copyOwnProperty: function(name, source, target) {

  Polymer.Base.chainObject = function(object, inherited) {

@jfrazzano
Copy link

Eric, wow. Thanks. That's cool.

@tjsavage tjsavage added the 1.x label Sep 8, 2016
@jaichandra
Copy link

jaichandra commented Mar 24, 2017

I have been trying to do this for a while and I finally got a version working. Here's the link: https://plnkr.co/edit/S3hwK5?p=preview. This certainly has limitations and I have only tested these with paper-elements, but it works for me so far. Below is the mixin for quick review:

Polymer.TemplateMixin = (element) => {
    let superClass = document.createElement(element).constructor;
    return class extends superClass {

        static get template() {
            if (!this.hasOwnProperty('_template')) {
                this._template = Polymer.DomModule.import(this.is, 'template') ||
                    Object.getPrototypeOf(this.prototype).constructor.template;
            }
            return this._template;
        }

        static finalize() {
            if (!this.hasOwnProperty('_template')) {
                let superTemplate = superClass.template;
                let cssText = Polymer.StyleGather.cssFromTemplate(this.template.cloneNode(true));
                if (cssText) {
                    let style = document.createElement('style');
                    style.textContent = cssText;
                    let sNode = this.getLastStyleNode(superTemplate);
                    if (sNode) {
                        sNode.insertAdjacentElement('afterend', style);
                    } else {
                        superTemplate.content.insertBefore(style, superTemplate.content.firstChild);
                    }
                }
                this._template = superTemplate.cloneNode(true);
            }
            super.finalize();
        }

        static getLastStyleNode(template) {
            let styles = template.content.querySelectorAll('style');
            return styles[styles.length - 1];
        }
    }
}

@kristianmandrup
Copy link

@jaichandra
Sweet :) I hope this gets built in with Polymer 2.0 at some point.

@jaichandra
Copy link

The above code certainly has performance limitations. I would need help figuring out a much cleaner way in Polymer to ensure each component does this template merge only once.

@kristianmandrup
Copy link

I created this Polymer extension years ago.
Allows a Polymer 1.0 element to be extended.

var myElement = Polymer.findRegistered('my-element');

  // Each key: properties, props, methods act as a mixin.
  // properties - properties object
  // props - all attributes (non-functions)
  // methods: - all own functions
  // behaviors: - all own functions and attributes
  var myExtension = Polymer.extend({
    parent: myElement,
    // properties: myElement.properties,
    // props: myElement.props,
    // methods: myElement.methods,
    // behaviors: myElement.behaviors
  }, {
    is: 'ext-element',
  });

  Polymer(myExtension);

@jaichandra
Copy link

@kristianmandrup I got the performance issue fixed. Updated above code with latest.

@TimvdLippe
Copy link
Contributor

This has shipped with the native API of customElements.get and inheritance with ES6 class extension 🎉

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

8 participants