Overrided Overrided - 3 years ago 219
AngularJS Question

AngularJS module.controller vs $controllerProvider.register

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
?

Answer Source

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 evaled, 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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download