Skip to content

Instantly share code, notes, and snippets.

@texel
Created June 30, 2016 17:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save texel/5fd8d9485cdea11919bc8c36957220e1 to your computer and use it in GitHub Desktop.
Save texel/5fd8d9485cdea11919bc8c36957220e1 to your computer and use it in GitHub Desktop.
import {Observable} from 'rxjs';
/**
* A decorator for Angular 2 component instance properties that enables
* them to automatically receive values from an Observable of the same type.
*
* In many cases, it's easier to deal with bare values in a view, while
* pushing value changes from an Observable. `Sink()` wraps up this pattern
* and automatically manages subscription disposal.
*
* By default, `@Sink()` will subscribe to a property with the same
* name appended with a `$`. If you pass a string to `Sink()`, it will
* subscribe to that property name instead.
*
* ### Example
*
* This component uses the property `counter` in its view, which is populated
* by the Observable `counter$` behind the scenes.
*
* ```typescript
* @Component(
* selector: 'simple-counter',
* template: `<div>{{ counter }}</div>`
* )
* export class FooComponent {
* constructor() { }
*
* public counter$: Observable<number> = Observable.interval(100);
* @Sink() counter: number;
*
* // If the Observable and property names don't match, pass a string
* // to `Sink()` to give it the Observable name.
* public counterObservable$: Observable<number> = Observable.interval(200);
* @Sink('counterObservable$') otherCounter: number;
* }
* ```
* @param {string} [name]
* @returns
*/
export function Sink(name?: string) {
return function (target: any, key: string) {
let sourceName = name || `${key}$`;
let subscriptionName = `${key}Subscription`;
let internalSourceName = `_${sourceName}`;
Object.defineProperty(target, sourceName, {
get() {
return this[internalSourceName];
},
set(value: Observable<any>) {
this[internalSourceName] = value;
this[subscriptionName] = value.subscribe(v => {
this[key] = v;
});
}
});
let originalOnDestroy = target.ngOnDestroy;
target.ngOnDestroy = function () {
let subscription = this[subscriptionName];
if (subscription) {
console.debug('Destroying subscription:', subscriptionName);
subscription.unsubscribe();
}
if (originalOnDestroy) {
originalOnDestroy.call(this);
}
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment