Created
September 5, 2015 20:41
-
-
Save sirbarrence/fd96e680b8db0d4ba27a 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
diff --git a/rxDecorateDirective.js b/rxDecorateDirective.js | |
index 56912ca..1ecb8b5 100644 | |
--- a/rxDecorateDirective.js | |
+++ b/rxDecorateDirective.js | |
@@ -1,4 +1,7 @@ | |
+'use strict'; | |
+ | |
function rxDecorateDirective($provide, directiveName) { | |
+ // Duck-typing function lifted from the rx.js source. | |
function isObservable(obj) { | |
return obj && typeof obj.subscribe === 'function'; | |
} | |
@@ -16,76 +19,65 @@ function rxDecorateDirective($provide, directiveName) { | |
return function postLink(scope, iElement, iAttrs) { | |
var originalScope = scope; | |
- var originalLinkArgs = arguments; | |
- | |
- // Make a new child scope that we'll pass along to the original directive link | |
- // function instead of the actual scope. If we receive an Observable to subscribe | |
- // to, we'll be able to update the child scope the original directive is watching | |
- // without modifying the original scope. If we receive anything else, we simply let | |
- // prototypal inheritance propagate the change from the original scope to the child | |
- // scope. | |
- var childScope = originalScope.$new(false); | |
+ var linkArgs = arguments; | |
- // Replace `originalScope` with `childScope` in the link function args, used when | |
- // calling the original link function with `apply()` below. | |
- originalLinkArgs[0] = childScope; | |
- | |
- // Name of the scope property containing the thing we need to watch. | |
- var propertyName = iAttrs[directiveName]; | |
+ // Expression in the directive's attribute value we need to watch. | |
+ var attrExpression = iAttrs[directiveName]; | |
// If the current scope property value is null or undefined, watch for the first | |
- // value that isn't. Otherwise, go ahead and use the current value. | |
- if (isUndefinedOrNull(originalScope[propertyName])) { | |
- originalScope.$toObservable(propertyName) | |
- .pluck('newValue') | |
- .skipWhile(isUndefinedOrNull) | |
- .first() | |
- .subscribe(onFirstUsefulValue); | |
- } else { | |
- onFirstUsefulValue(); | |
- } | |
+ // value that isn't, in case it's an Observable. | |
+ originalScope.$toObservable(attrExpression) | |
+ .pluck('newValue') | |
+ .skipWhile(function isUndefinedOrNull(value) { | |
+ return typeof value === 'undefined' || value === null; | |
+ }) | |
+ .first() | |
+ .subscribe(function onFirstUsefulValue(firstValue) { | |
+ // If we're bound to an Observable, subscribe to it. | |
+ if (isObservable(firstValue)) { | |
+ // The property name we want the original directive linking function to | |
+ // set a watcher on. | |
+ var RX_VALUE_SCOPE_PROPERTY = '$$rxValue'; | |
+ | |
+ // Get a shared version of the value stream we're bound to, since we'll | |
+ // be making multiple subscriptions. | |
+ var valueStream = firstValue.share(); | |
- // A stream of the new values that the watcher might produce if we need to use it. | |
- //var watchedValueStream = originalScope.$toObservable(propertyName) | |
- // .pluck('newValue'); | |
+ // Create a new isolate scope to pass to the original linking function. | |
+ var isolateScope = originalScope.$new(true); | |
- function isUndefinedOrNull(value) { | |
- return typeof value === 'undefined' || value === null; | |
- } | |
+ // Replace `originalScope` with `isolateScope` in the link function | |
+ // args, used when calling the original link function with `apply()` | |
+ // below. | |
+ linkArgs[0] = isolateScope; | |
- function onFirstUsefulValue() { | |
- // If we're bound to an Observable, subscribe to it. | |
- if (isObservable(originalScope[propertyName])) { | |
- // Get a shared version of the value stream we're bound to, since we'll | |
- // be making multiple subscriptions. | |
- var valueStream = originalScope[propertyName].share(); | |
+ // Replace the original directive name attribute value with the | |
+ // property name we want the original directive to watch instead. | |
+ iAttrs.$set(directiveName, RX_VALUE_SCOPE_PROPERTY); | |
- // Invoke the original linking function once, the first time we | |
- // get a value from the Observable. | |
- valueStream.first().subscribe(function() { | |
- originalLinkFn.apply(directiveConfig, originalLinkArgs); | |
- }); | |
+ // Invoke the original linking function with the modified link args we | |
+ // prepared earlier. | |
+ originalLinkFn.apply(directiveConfig, linkArgs); | |
- // Subscribe to the Observable, updating the child scope property the | |
- // original linking function code is watching whenever we receive a new | |
- // value. | |
- var valueStreamDisposable = valueStream | |
- .safeApply(childScope, function onNextValue(value) { | |
- childScope[propertyName] = value; | |
- }) | |
- .subscribe(); | |
+ // Subscribe to the Observable, updating the child scope property the | |
+ // original linking function code is watching whenever we receive a new | |
+ // value. | |
+ var valueStreamDisposable = valueStream | |
+ .safeApply(isolateScope, function onNextValue(value) { | |
+ isolateScope[RX_VALUE_SCOPE_PROPERTY] = value; | |
+ }) | |
+ .subscribe(); | |
- // Our subscription should not live longer than the scope. | |
- originalScope.$on('$destroy', function() { | |
- valueStreamDisposable.dispose(); | |
- }); | |
- } else { | |
- // Else the directive is not bound to an Observable, so the child scope will | |
- // prototypally inherit the changes to the parent and the original directive's | |
- // watcher should work normally. | |
- originalLinkFn.apply(directiveConfig, originalLinkArgs); | |
- } | |
- } | |
+ // Our subscription should not live longer than the scope. | |
+ originalScope.$on('$destroy', function() { | |
+ valueStreamDisposable.dispose(); | |
+ }); | |
+ } else { | |
+ // Else the directive is not bound to an Observable, so we call the | |
+ // original linking function with its original args. | |
+ originalLinkFn.apply(directiveConfig, linkArgs); | |
+ } | |
+ }); | |
}; | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment