Skip to content

Instantly share code, notes, and snippets.

@dliebner
Last active January 30, 2023 04:01
Show Gist options
  • Save dliebner/d745f83e1df467a2f12747aba6fb2dcf to your computer and use it in GitHub Desktop.
Save dliebner/d745f83e1df467a2f12747aba6fb2dcf to your computer and use it in GitHub Desktop.
/**
* Notifies ancestor of drilled property update via event
*/
class DrilledPropertyUpdateEventController {
static customEventName = 'lit-drilled-property-update';
/** @type {HTMLElement} */
host;
/**
* @param {ControllerHost} host
* @param {string} drilledProperty
*/
constructor(host, drilledProperty) {
// Store a reference to the host
this.host = host;
// Register for lifecycle updates
host.addController(this);
/** @type {string} */
this.drilledProperty = drilledProperty;
}
/** @param {CustomEvent} e */
_handleCustomEvent = (e) => {
if( e.detail.drilledProperty === this.drilledProperty ) {
e.stopPropagation();
if( e.detail.proxiedUpdate ) {
// newValue is a callback
this.host[this.drilledProperty] = e.detail.newValue( this.host[this.drilledProperty] );
} else {
// newValue is the new value
this.host[this.drilledProperty] = e.detail.newValue;
}
}
};
hostConnected() {
this.host.addEventListener(this.constructor.customEventName, this._handleCustomEvent);
}
hostDisconnected() {
this.host.removeEventListener(this.constructor.customEventName, this._handleCustomEvent);
}
/**
* @param {HTMLElement} descendantEl
* @param {string} drilledProperty
* @param {*} newValue
* @param {boolean} proxiedUpdate Set to true to pass a callback as newValue which accepts the drilledProperty value as a parameter and returns the mutated version
*/
static dispatchUpdateFromDescendant( descendantEl, drilledProperty, newValue, proxiedUpdate = false ) {
if( proxiedUpdate && typeof newValue !== 'function' ) throw "Tried to dispatch a proxied update from descendant, but newValue was not a callback type";
descendantEl.dispatchEvent(
new CustomEvent(this.customEventName, {
bubbles: true,
composed: true,
detail: {
drilledProperty,
newValue,
proxiedUpdate
}
})
);
}
}
class ParentElementWithDrilledProperty extends LitElement {
static properties = {
foo: {state: true},
};
constructor() {
super();
this.foo = {
bax: 'baz'
};
/** Allows descendants to update this.foo */
this.fooUpdateController = new DrilledPropertyUpdateEventController(this, 'foo');
}
render() {
return html`
<my-child-element .foo=${this.foo}></my-child-element>
`;
}
}
customElements.define('my-parent-element', ParentElementWithDrilledProperty);
class ChildElementWithDrilledProperty extends LitElement {
static properties = {
foo: {state: true},
};
_handleClick() {
DrilledPropertyUpdateEventController.dispatchUpdateFromDescendant(
this,
'foo',
{
bax: 'cool'
}
);
}
render() {
return html`
<div @click=${this._handleClick}>
My bax is so ${this.foo.bax}!
</div>
`;
}
}
customElements.define('my-child-element', ChildElementWithDrilledProperty);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment