17

class A extends HTMLElement {
  constructor() {
    super()
    return new Proxy(this, {})
  }
}

window.customElements.define('a-element', A)
<a-element></a-element>

How can i Proxy custom element?

When i try it:

Uncaught InvalidStateError: custom element constructors must call super() first and must not return a different object.

1
  • I have custom elements which comprise two input fields: a primary and a secondary one. I thought I could proxy the return value like you did because I wanted to forward all HTMLInputElement prototype property lookups to the primary input, save for a select few, without having to write get prop(){ return this.#primary.prop; } set prop(x){ this.#primary.prop = x; } 50 times. Solved it without Proxies by doing this in my module: export const Custom = (class Custom extends HTMLElement{ #primary; static init(){ /* Add getters on `this.prototype` accessing `this.#primary`. */ } }).init();. Commented Oct 21, 2022 at 1:11

1 Answer 1

10

You can either Proxify a class or an instance of a Custom Element.

Given the following Custom Element definition:

class A extends HTMLElement {
  constructor() {
    super()
  }
  connectedCallback() {
    this.innerHTML = 'Hello'    
  }
}
customElements.define( 'a-element', A )

Proxy for a Custom Element instance

Create a Proxy from an instance reference (here: ae):

<a-element id="ae"></a-element>
<script>
  var b1 = new Proxy( ae, {
    get ( target, value ) { return target[value] }       
  } )
  console.log( b1.innerHTML ) // => "Hello"
</script>

Proxy for a Custom Element class

Define the construct trap to catch the new operator:

<script>
  var B = new Proxy( A, {
    construct() { return new A }
  } )
  var b2 = new B
  document.body.appendChild( b2 )
  console.log( b2.innerHTML ) // => "Hello"
</script>

Get a Custom Element instance Proxy from a class Proxy

If you want to instanciate a Custom Element and get one Proxy object directly, you can combine both solutions above.

The following example shows how to get a Proxy for element <a-element> that will log in the console each property access. The construct() trap defined in the class Proxy returns itself a Proxy for the instanciated Custom Element.

class A extends HTMLElement {
  constructor() {
    super()
  }
  connectedCallback() {
    this.innerHTML = 'Hello'    
  }
}
customElements.define( 'a-element', A )		

var P = new Proxy( A, {
  construct () { 
    return new Proxy ( new A, {
      get ( target, value ) { 
        if ( value == 'element' ) 
          return target
        console.info( `proxy: property ${value} for <${target.localName}> is "${target[value]}"` )
        return target[value]
      }       
    } )
  }
} )
var p = new P
document.body.appendChild( p.element )
console.log( p.innerHTML )

Sign up to request clarification or add additional context in comments.

7 Comments

I need to encapsulate the logic of the proxy, in the superclass. Like: function P (_class) { return new Proxy (new class extends _class {}, {}) } class A extends P(HTMLElement) {} customElements.define( 'a-element', A ) But it doesn't work too
@АртурЛаврищев use function P (_class) { return new Proxy (class extends _class {}, {}) } instead (without new before class)
@АртурЛаврищев thanks for the accepted answer, you can upvote if it helped :-)
Thank you so much for this answer. It turned on a lightbulb in my head - there are so many code problems Ive been struggling with for months that might just be elegantly solved by these techniques...
@diopside Just curious, what code problems are you looking to solve with these Proxy techniques?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.