Archive

Archive for November, 2016

Knockout.js: Subscription that fires only once

November 16th, 2016 No comments

    It might be useful sometimes to have an observable subscription, which fires only once. The straightforward implementation is to use kind of “already fired” internal flag that would prevent a handler from being called more than once. It’s not the best approach though, as the subscription itself remains alive and continues firing every time the value has mutated. Much more efficient solution is to “kill” subscription by disposing it at the first call:

ko.subscribable.fn.subscribeOnce = function (handler, target, event) {
    var subscription = this.subscribe(function (newValue) {
        subscription.dispose(); // remove subscription, so it won't fire further
        handler(newValue);
    }, target, event);

    return subscription; // mimic the normal "subscribe" by returning the subscription
};

In case of computed observables, it gives even more benefits since it also removes all underlying subscriptions to other observables the computed observable depends on.

In TypeScript this will be an extension to the KnockoutSubscribableFunctions<T> interface

// knockoutjs-extensions.d.ts
interface KnockoutSubscribableFunctions<T> {
    subscribeOnce(callback: (newValue: T) => void, target?: any, event?: string): KnockoutSubscription;
    subscribeOnce<TEvent>(callback: (newValue: TEvent) => void, target: any, event: string): KnockoutSubscription;
}

TypeScript has the “declaration merging” concept, so the interfaces are “open-ended”. That means two or more separate declarations with the same name are to be merged by compiler into a single one. Note, to be effective the declaration has to be placed in a TypeScript Declaration File (*.d.ts).

Below is a usage example

...
private someObservable: KnockoutObservable<SomeType> = ko.observable(null);
...
this.someObservable.subscribeOnce(newVal => {
	// do something here
});