Created
August 30, 2013 22:02
-
-
Save alexkunin/6394739 to your computer and use it in GitHub Desktop.
Solution to https://github.com/angular-ui/ui-router/pull/73, sugar-enabled alternative to https://gist.github.com/MattWalker/6106393. Includes "dependency reordering' (sort of) and circular reference checks.
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
angular.module("yourApp").provider("$stateProviderWrapper", function ($stateProvider, $injector) { | |
var stack = { | |
"":{} | |
}; | |
return { | |
$get:function () { | |
}, | |
state:function (name, definition) { | |
// Apply same argument manipulations as $stateProvider.state does | |
if (angular.isObject(name)) { | |
definition = name; | |
} else { | |
definition.name = name; | |
} | |
// Look for all things to resolve | |
var resolves = {}; | |
if (definition.resolve) { | |
resolves[""] = definition.resolve; | |
} | |
if (definition.views) { | |
angular.forEach(definition.views, function (view, name) { | |
if (view && view.resolve) { | |
resolves[name] = view.resolve; | |
} | |
}); | |
} | |
// Make sure everything is invokable | |
angular.forEach(resolves, function (resolve) { | |
angular.forEach(resolve, function (value, name) { | |
if (angular.isString(value)) { | |
resolve[name] = function () { | |
return $injector.get(value); | |
}; | |
} | |
}); | |
}); | |
// Enhance everything | |
angular.forEach(resolves, function (resolve, viewName) { | |
// Create unique map (dependency -> deferred), inherit from parent state | |
var deferred = stack[name + "/" + viewName] = stack[name + "/" + viewName] || (function () { | |
var f = function () {}, | |
parentName = ""; | |
if (!angular.isDefined(definition.parent)) { | |
var compositeName = /^(.+)\.[^.]+$/.exec(name); | |
if (compositeName != null) { | |
parentName = compositeName[1]; | |
} | |
} else if (definition.parent != null) { | |
parentName = definition.parent.name || definition.parent; | |
} | |
f.prototype = stack[parentName + "/"] || stack[""] || {}; | |
return new f(); | |
}()); | |
function depends(a, b, seen) { | |
if (!resolve[a]) { | |
throw new Error("Unresolved dependency \"" + a + "\""); | |
} | |
if (!seen) { | |
seen = []; | |
} | |
if (seen.indexOf(a) != -1) { | |
throw new Error("Circular dependency: " + seen.concat([ a ]).join(" -> ")); | |
} | |
return $injector.annotate(resolve[a]).some(function (name) { | |
if ($injector.has(name)) { | |
return false; | |
} | |
return resolve[name] && (name == b || depends(name, b, seen.concat([ a ]))); | |
}); | |
} | |
Object.keys(resolve).sort(function (a, b) { | |
return depends(a, b) ? 1 : depends(b, a) ? -1 :0; | |
}).forEach(function (name) { | |
var resolver = resolve[name]; | |
resolve[name] = function ($q, $injector, $stateParams) { | |
if (!deferred.hasOwnProperty(name)) { | |
deferred[name] = $q.defer(); | |
} | |
var input = { | |
$stateParams:$stateParams | |
}; | |
$injector.annotate(resolver).forEach(function (name) { | |
if (!$injector.has(name)) { | |
if (!deferred[name]) { | |
if (!resolve[name]) { | |
// Let $injector.invoke deal with this property | |
return; | |
} else { | |
deferred[name] = $q.defer(); | |
} | |
} | |
input[name] = deferred[name].promise; | |
} | |
}); | |
return $q.all(input).then(function (output) { | |
return $q.when($injector.invoke(resolver, definition, output)).then(function (result) { | |
deferred[name].resolve(result); | |
return result; | |
}); | |
}); | |
}; | |
resolve[name].$inject = [ "$q", "$injector", "$stateParams" ]; | |
}); | |
}); | |
$stateProvider.state(name, definition); | |
return this; | |
} | |
}; | |
}); |
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
angular.module("yourApp").config(function ($stateProviderWrapperProvider) { | |
$stateProviderWrapperProvider | |
.state("parent", { | |
resolve:{ | |
a:function () { | |
return 1; | |
}, | |
b:function (a) { | |
return a + 1; | |
} | |
} | |
}) | |
.state("parent.child", { | |
resolve:{ | |
c:function (a, b) { | |
return a * b; | |
} | |
} | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment