Last active
August 29, 2015 14:08
-
-
Save alextkachman/bda667b09c0c4b7f9ee8 to your computer and use it in GitHub Desktop.
Patch for injector to resolve promises
This file contains hidden or 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
(function(angular){ | |
"use strict"; | |
/** | |
* Patched $injector.invoke | |
* | |
* It allows in many situations to avoid promise related boilerplate like | |
* | |
* factory('$loggedUser',['$login','$loadedConfig',function($login,$loadedConfig){ | |
* return $login.then(function($login){ | |
* return $loadedConfig.then(function($loadedConfig){ | |
* return createLoggedUser($login,$loadedConfig) | |
* }) | |
* }) | |
* ]) | |
* | |
* or alternatively | |
* | |
* factory('$loggedUser',['$login','$loadedConfig','$q',function($login,$loadedConfig,$q){ | |
* return $q.all({$login:$login,$loadedConfig:$loadedConfig{).then(function(resolved){ | |
* return createLoggedUser(resolved.$login,resolved.$loadedConfig) | |
* }) | |
* ]) | |
* | |
* and simply use instead | |
* | |
* factory('$loggedUser',['@$login','@$loadedConfig',function($login,$loadedConfig){ | |
* return createLoggedUser($login,$loadedConfig) | |
* ]) | |
* | |
* If any of services required for annotated function is prefixed with @ char | |
* - each such service treated as promise | |
* - the function automatically converted in to the one returning promise | |
* - the function will be executed after all such promise-services resolved | |
* - return value of original function will become resolved value of final function | |
*/ | |
angular.module('InjectorEx',[]) | |
.run(['$injector','$q',function($injector,$q) { | |
function doPatch(fn,fnToCall) { | |
var i, ii, | |
patched | |
for (i = 0, ii = fn.length - 1; i != ii; ++i) { | |
if (fn[i].charAt(0) == '@') { | |
//noinspection JSUnusedAssignment | |
(patched || (patched = [])).push(i) | |
} | |
} | |
if (patched) { | |
fn = fn.slice() | |
for (i = 0, ii = patched.length; i != ii; ++i) { | |
fn[patched[i]] = fn[patched[i]].substring(1) | |
} | |
fn [fn.length - 1] = function () { | |
var resolve = [], | |
origThis = this, | |
i, | |
newArgs | |
for (i = 0; i != patched.length; ++i) { | |
resolve.push(arguments[patched[i]]) | |
} | |
newArgs = Array.prototype.slice.call(arguments) | |
return $q.all(resolve).then(function (resolved) { | |
for (var i = 0, ii = patched.length; i != ii; ++i) { | |
newArgs[patched[i]] = resolved[i] | |
} | |
return fnToCall.apply(origThis, newArgs) | |
}) | |
} | |
} | |
return fn | |
} | |
function patch(fn) { | |
if (!angular.isArray(fn)) { | |
return fn | |
} | |
var fnToCall = fn[fn.length-1] | |
return fnToCall.$$patch || (fnToCall.$$patch = doPatch(fn,fnToCall)) | |
} | |
$injector.invoke = (function(){ | |
var orig$invoke = $injector.invoke | |
return function invoke(fn, self, locals){ | |
return orig$invoke.call(this, patch(fn), self, locals) | |
} | |
})() | |
/** | |
* We patch instantiate exclusively in order to use patched invoke | |
*/ | |
$injector.instantiate = function instantiate(Type, locals) { | |
var Constructor = function() {}, | |
instance, | |
returnedValue; | |
Constructor.prototype = (angular.isArray(Type) ? Type[Type.length - 1] : Type).prototype; | |
instance = new Constructor(); | |
/* | |
* This line is suppose to be the only material diff with original function | |
*/ | |
returnedValue = $injector.invoke(Type, instance, locals); | |
return angular.isObject(returnedValue) || angular.isFunction(returnedValue) ? returnedValue : instance; | |
} | |
}]) | |
})(angular); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment