Search code examples
javascriptclassecmascript-6web-componentcustom-element

Creating new element with a dynamic extends class expression


Is it possible to pass a class expression as parameter?

Have not tried the eval route yet..

// CardtsElements.Zone contains a valid class expression
// used to create a valid Zone Custom Element
let extend = (source, name, definitionClassExpression) => 
    customElements.define('CARDTS-' + name, 
                           class extends CardtsElements[source] definitionClassExpression);
                                                              ^^^^SYNTAX ERROR^^^^^^^^^^

// Create a new 'CARDTS-FOUNDATION' element extending 'CARDTS-ZONE'
extend('Zone','Foundation', {
    static get observedAttributes() {
        return ['suit','draggable','drop'];
    }
    constructor(){}
});

Solution

  • You can pass your class expression as a class factory function:

    • a (arrow) function,
    • with one parameter (superclass): the class you want to extend,
    • that will return the new derived class.

    // CardtsElements.Zone contains a valid class expression
    // used to create a valid Zone Custom Element
    var CardtsElements = {
      'Zone': class extends HTMLElement {
          constructor() { super() ; console.log('zone element created') }
          connectedCallback(){ console.log('connected Zone')}
          zone() { console.log( 'zone' ) }
      }
    }
    
    let extend = (source, name, classFactory) => 
        customElements.define('cardts-' + name, classFactory(CardtsElements[source])) 
    
    
    // Create a new 'CARDTS-FOUNDATION' element extending 'CARDTS-ZONE'
    extend('Zone','foundation', superclass => 
         class extends superclass {
             constructor() { super() ; console.log(this.localName + ' created') }
             static get observedAttributes() { return ['suit','draggable','drop'] }
             connectedCallback(){ 
                super.connectedCallback();
                console.log('connected',this.localName)
             }
             foundation() { console.log('foundation') }
         }
    )
    
    CF.zone()
    CF.foundation()
    <cardts-foundation id=CF>Cardts Foundation</cardts-foundation>