Skip to content

Instantly share code, notes, and snippets.

@justinfagnani
Created March 4, 2020 22:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinfagnani/d7f73971bfa3c96d5a08f9dadda6ea08 to your computer and use it in GitHub Desktop.
Save justinfagnani/d7f73971bfa3c96d5a08f9dadda6ea08 to your computer and use it in GitHub Desktop.
Observable LitElement
class ExampleElement extends ObservableLitElement {
@property()
src: string;
@observe('src')
protected async _onSrcChange() {
// fetch the new URL...
}
}
/**
* @license
* Copyright (c) 2020 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at
* http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at
* http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
import {LitElement, PropertyValues} from 'lit-element';
export * from 'lit-element';
export type Observer = () => void;
export interface ObservableLitElementConstructor {
new (): ObservableLitElement;
_observers: Map<PropertyKey, Observer[]>;
}
export abstract class ObservableLitElement extends LitElement {
update(changedProperties: PropertyValues) {
const clazz = this.constructor as ObservableLitElementConstructor;
if (clazz._observers !== undefined) {
// Collect all observers triggered by this batch of property changes
const observersToRun = new Set<Observer>();
for (const propertyName of changedProperties.keys()) {
const observers = clazz._observers.get(propertyName);
if (observers !== undefined) {
for (const observer of observers) {
observersToRun.add(observer);
}
}
}
// Run the observers
for (const observer of observersToRun) {
observer.call(this);
}
}
super.update(changedProperties);
}
}
export function observe(...propertyNames: string[]) {
return (proto: any, method: string) => {
const clazz = proto.constructor as DesignerElementConstructor;
if (!clazz.hasOwnProperty('_observers')) {
Object.defineProperty(clazz, '_observers', {value: new Map()});
}
for (const property of propertyNames) {
let observers = clazz._observers.get(property);
observers ?? clazz._observers.set(property, (observers = []));
observers.push(clazz.prototype[method]);
}
};
}
@paladox
Copy link

paladox commented Nov 25, 2021

Does this support stuff like src.* too? E.g. sub properties?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment