I'm trying to add controller dynamically in my AngularJS application.
On sub-domain, I have anotherController.js
file.
Here's anotherController.js
content:
function anotherControllerWrapper() {
return ['$scope', '$state', function ($scope, $state) {
$scope.doWork = function () {
//...doing some work...
alert('work done');
};
$scope.doWork();
}];
};
Also I have wrote runtimeController
provider to be able to use $controllerProvider
in runtime:
app.provider('runtimeController', function () {
var controllerProvider = null;
this.setControllerProvider = function (cp) {
controllerProvider = cp;
};
this.$get = function () {
return {
registerController: function (controllerName, controllerConstructor) {
if (!controllerProvider.has(controllerName)) {
controllerProvider.register(controllerName, controllerConstructor);
}
}
};
};
});
Here's config
section of application:
app.config(function($controllerProvider, runtimeControllerProvider) {
runtimeControllerProvider.setControllerProvider($controllerProvider);
});
I'm receiving controller's code over http (inside another controller), so it looks like this:
app.controller('testController', ['$scope', '$state', '$http', 'runtimeController',
function ($scope, $state, $http, runtimeController) {
$http.get('http://someUrl/anotherController.js')
.then(
function(sucess){
var evaluated = new Function('return ' + success.data)();
var ctrl = evaluated();
// routing to ui state with specified 'anotherController' works
// no 'anotherController' in app._invokeQueue
runtimeController.registerController('anotherController', ctrl);
// routing to ui state with specified 'anotherController' constanly fails
// 'anotherController' appears in app._invokeQueue
//app.controller('anotherController', ctrl);
//--registering new UI route with 'anotherController' as controller here
$state.go('anotherState');
},
function(error){ alert('something went wrong!'); },
);
}]);
Ui states are also added dymanically, after I'm adding controller.
Can someone explain me please, what's happening and what's difference between $controllerProvider.register
and module.controller
?
Module methods (controller
, directive
, etc) result in adding a config block (_configBlocks
) that is executed on application initialization. Once the application has passed config phase, it won't execute newly added config blocks, so app.controller(...)
has no effect during run phase.
As this example shows, runtimeController
implementation can be simplified to
app.config(($provide, $controllerProvider) => {
$provide.value('$controllerProvider', $controllerProvider);
});
eval
should be avoided for numerous reasons. Considering that the script is loaded from a domain that is allowed by CORS and doesn't require to be eval
ed, a suitable alternative is to load it as a script. This will require to patch AngularJS API to allow late component registrations, similarly to how ocLazyLoad does - or just use ocLazyLoad, because it already does that.