Note: This implementation is based on RxJS 4.0
Heavy use of observables can result in many components with duplicate boilerplate code for subscribing
to an @Input
observable and assigning the value(s) to another property for use in the template. This
might also involve juggling property names if you want to use the same semantic naming in both the
component's API and template. Additionally, some defensive boilerplate is necessary to guard against
the possibility of differing synchronous and asynchronous behaviour.
@Subscribe()
sets up a combo get
/set
on the decorated property. Observables get assigned to the
property, and the latest value is gotten from it. The observable reference is closed over and not
otherwise accessible.
@SubscribeTo(property)
overrides the observable property with a setter to trap and subscribe to the
new observable. The observable remains accessible via a getter. Values are assigned to the property
that is decorated.
Both will look for an instance of ChangeDetectorRef
on the component and call markForCheck
if found.
Update: These are both combined into the same decorator, hinging simply on whether a property name is passed as an argument.
- Handle subscribe for observables on an observable-by-observable and component-by-component basis.
- Use the async pipe in conjunction with the
?
operator for each use of the property in the template. - The same technique could probably be implemented as a factory method rather than a decorator.
Zone.run is needed to account for the fact that an asynchronous observable will execute its callback outside of the angular zone, making changes that won't get automatically picked up since no CD cycle is kicked off as a consequence. Because zone.run causes an error if the observable is not asynchronous, subscriptions are made uniformly asynchronous with observeOn
. See https://gist.github.com/endash/1f961830d0c5b744598a for futher discussion of the issue.
- Using
window.zone
to wrap the subscriber callbacks. This turns out to be the appropriate zone, but that may only be because we're in a setter for a property binding. - Can only have one
@SubscribeTo
per observable. - Must inject ChangeDetectorRef Because the observable callback is a "purely internal" change (i.e. not a binding) we have to manually trigger the check. IF all parent components are set to the default CD strategy CD will work without it, but if there's an
OnPush
component anywhere above the component it will break.