Created
June 30, 2016 17:50
-
-
Save texel/5fd8d9485cdea11919bc8c36957220e1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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