dees-element/ts/directives/classes.subscribewithtemplate.ts

51 lines
1.6 KiB
TypeScript

import { type TemplateResult, noChange } from 'lit';
import { AsyncDirective, directive } from 'lit/async-directive.js';
import { rxjs } from '@push.rocks/smartrx';
/**
* Subscribes to an observable and applies a template function to each emission.
* @param observable - the source Observable
* @param templateFn - function mapping each emitted value to a TemplateResult or other renderable content
*/
class SubscribeWithTemplateDirective extends AsyncDirective {
private observable?: rxjs.Observable<unknown>;
private templateFn?: (value: unknown) => TemplateResult | unknown;
private sub: rxjs.Subscription | null = null;
render(
observable: rxjs.Observable<unknown>,
templateFn: (value: unknown) => TemplateResult | unknown
) {
const changed = this.observable !== observable || this.templateFn !== templateFn;
if (changed) {
this.sub?.unsubscribe();
this.observable = observable;
this.templateFn = templateFn;
if (this.isConnected) {
this.startSubscription();
}
}
return noChange;
}
private startSubscription() {
this.sub = this.observable!.subscribe((v: unknown) => {
const out = this.templateFn!(v);
this.setValue(out);
});
}
disconnected() {
this.sub?.unsubscribe();
}
reconnected() {
this.startSubscription();
}
}
/**
* Directive that renders templates for each emission of an Observable.
* Usage: html`${subscribeWithTemplate(myObservable, v => html`<span>${v}</span>`)}`
*/
export const subscribeWithTemplate = directive(SubscribeWithTemplateDirective);