AngularAMD + ui-router + dynamic controller name?
Solution 1:
This is a link to working plunker.
solution
We need two features of the UI-Router:
- resolve (to load the missing pieces of js code)
- controllerProvider (see cites from documentation below)
angularAMD - main.js definition
This would be our main.js, which contains smart conversion controllerName - controllerPath:
require.config({
//baseUrl: "js/scripts",
baseUrl: "",
// alias libraries paths
paths: {
"angular": "angular",
"ui-router": "angular-ui-router",
"angularAMD": "angularAMD",
"DefaultCtrl": "Controller_Default",
"OtherCtrl": "Controller_Other",
},
shim: {
"angularAMD": ["angular"],
"ui-router": ["angular"],
},
deps: ['app']
});
controllers:
// Controller_Default.js
define(['app'], function (app) {
app.controller('DefaultCtrl', function ($scope) {
$scope.title = "from default";
});
});
// Controller_Other.js
define(['app'], function (app) {
app.controller('OtherCtrl', function ($scope) {
$scope.title = "from other";
});
});
app.js
Firstly we would need some method converting the param (e.g. id) into controller name. For our test purposes let's use this naive implementation:
var controllerNameByParams = function($stateParams)
{
// naive example of dynamic controller name mining
// from incoming state params
var controller = "OtherCtrl";
if ($stateParams.id === 1) {
controller = "DefaultCtrl";
}
return controller;
}
.state()
And that would be finally our state definition
$stateProvider
.state("default", angularAMD.route({
url: "/{id:int}",
templateProvider: function($stateParams)
{
if ($stateParams.id === 1)
{
return "<div>ONE - Hallo {{title}}</div>";
}
return "<div>TWO - Hallo {{title}}</div>";
},
resolve: {
loadController: ['$q', '$stateParams',
function ($q, $stateParams)
{
// get the controller name === here as a path to Controller_Name.js
// which is set in main.js path {}
var controllerName = controllerNameByParams($stateParams);
var deferred = $q.defer();
require([controllerName], function () { deferred.resolve(); });
return deferred.promise;
}]
},
controllerProvider: function ($stateParams)
{
// get the controller name === here as a dynamic controller Name
var controllerName = controllerNameByParams($stateParams);
return controllerName;
},
}));
Check it here, in this working example
documentation
As documented here: $stateProvider, for a state(name, stateConfig)
we can use controller
and controllerProvider
. Some extract from documentation:
controllerProvider
...
controller
(optional) stringfunction
Controller fn that should be associated with newly related scope or the name of a registered controller if passed as a string. Optionally, the ControllerAs may be declared here.
controller: "MyRegisteredController"
controller:
"MyRegisteredController as fooCtrl"}
controller: function($scope, MyService) {
$scope.data = MyService.getData(); }
controllerProvider
(optional) function
Injectable provider function that returns the actual controller or string.
controllerProvider:
function(MyResolveData) {
if (MyResolveData.foo)
return "FooCtrl"
else if (MyResolveData.bar)
return "BarCtrl";
else return function($scope) {
$scope.baz = "Qux";
}
}
...
resolve
resolve
(optional) object
An optional
map<string, function>
of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them ALL to be resolved before the controller is instantiated...
I.e. let's use controllerProvider
:
... to resolve the controller name dynamically...
In case, that you managed to get here, maybe you'd like to check another similar solution with RequireJS - angular-ui-router with requirejs, lazy loading of controller