lit / lit-element

LEGACY REPO. This repository is for maintenance of the legacy LitElement library. The LitElement base class is now part of the Lit library, which is developed in the lit monorepo.
https://lit-element.polymer-project.org
BSD 3-Clause "New" or "Revised" License
4.49k stars 318 forks source link

Hooking into connected and disconnected callbacks fails #1112

Closed philkunz closed 3 years ago

philkunz commented 3 years ago
import * as plugins from './domtools.plugins';
import { LitElement } from 'lit-element';

export class ElementInstrumenter {
  connectedElements = new plugins.lik.ObjectMap<LitElement>();

  public instrumentElement(elementArg: LitElement) {
    const originalConnectedCallback = elementArg.connectedCallback;
    const originalDisconnectedCallback = elementArg.disconnectedCallback;

    if (!elementArg.parentElement) {
      elementArg.connectedCallback = () => {
        this.connectedElements.add(elementArg);
        originalConnectedCallback.apply(elementArg);
      };
    } else {
      this.connectedElements.add(elementArg);
    }

    elementArg.disconnectedCallback = () => {
      this.connectedElements.remove(elementArg);
      originalDisconnectedCallback.apply(elementArg);
    };

  }

  public async forEachelement(eachFuncArg: (elementArg: LitElement) => Promise<void>) {
    for (const elementArg of this.connectedElements.getArray()) {
      await eachFuncArg(elementArg);
    }
  }
}

I have the above class. However hooking into the callbacks that way does not work. Any obvious reason why?

ChristianUlbrich commented 3 years ago

Either it's a race condition (you are instrumenting, after CustomElements have been defined and added) or it is an issue with prototypes. You are not showing the rest of your code (how and when do you instrument). At first glance, if you do instrumentation like that, I am betting, you are overwriting instance methods where you should override prototype methods.

An easier way would be class-based expression mixins (aka High Order Components) and I think this is the preferred way in LitElement itself for composition; they have a lot of advantages (working instanceof...); you'd collect the connected instances either in a closure or in a global.

philkunz commented 3 years ago

I solved it by writing an extension class for lit-element that would use connectedCallback und disconnectedCallback to emit events for connected and disconnected. This will then allow the instrumented to subscribe to those events and unsubscribe upon dom disconnection.