George Tsopanoglou George Tsopanoglou - 22 days ago 5
AngularJS Question

Angular: Why lazy-loading a decorator doesn't work?

Synchronously registering a decorator

angular
.module('myApp')
.decorator('$controller', MyDecorator);

angular
.module('myApp')
.controller('MyCtrl', MyCtrl);


Asynchronously registering a decorator

$timeout(function () {
angular
.module('myApp')
.register
.decorator('$controller', MyDecorator);

// Make sure controller is registered after decorator
$timeout(function () {
angular
.module('myApp')
.register
.controller('MyCtrl', MyCtrl);
}, 1000);
}, 1000);


Why doesn't the second example work?

Answer

As you know, AngularJS has 2 distinct phases during bootstrap:

  1. configuration phase
  2. run phase

From the official documentation:

A module is a collection of configuration and run blocks which get applied to the application during the bootstrap process. In its simplest form the module consists of a collection of two kinds of blocks:

  1. Configuration blocks - get executed during the provider registrations and configuration phase. Only providers and constants can be injected into configuration blocks. This is to prevent accidental instantiation of services before they have been fully configured.
  2. Run blocks - get executed after the injector is created and are used to kickstart the application. Only instances and constants can be injected into run blocks. This is to prevent further system configuration during application run time.

In the quote above I have highlighted the sentence about run blocks:

This is to prevent further system configuration during application run time

Now, in the AngularJS documentation about decorator:

Like with $provide.decorator, the module.decorator function runs during the config phase of the app. That means you can define a module.decorator before the decorated service is defined.

So the decoration of a controller (or service or filter) is done in the configuration phase not in the run phase.

For this reason your "asynchronously registering a decorator" example does not work: you are trying to define and decorate the controller inside the initCtrl function. But the latter is called in the run phase and it's too late to define new decorators in this phase.