Angularjs - Decorate Controllers

2019-02-10 18:28发布

问题:

I am trying to set up a decorator for my controllers. My intention is to introduce some common behaviour across all the controllers in my app.

I have it configured to work in Angular 1.2.x, but there are some breaking changes from 1.3.x onwards that is breaking the code. The error one now gets is "controller is not a function".

Below is the code for the decorator:

angular.module('myApp', ['ng'], function($provide) {
    $provide.decorator('$controller', function($delegate) {

        return function(constructor, locals) {

                //Custom behaviour code

                return $delegate(constructor, locals);
            }
        })
    });

Angular 1.2.x - http://jsfiddle.net/3v17w364/2/ (Working)
Angular 1.4.x - http://jsfiddle.net/tncquyxo/2/ (Broken)

回答1:

In Angular 1.4.x modules have decorator method, $provide.decorator is no longer needed.

For monkey-patching APIs it is always preferable to use arguments instead of enumerating them explicitly, the chance that it will break is much lesser.

angular.module('myApp', ['ng']).decorator('$controller', function ($delegate) {
    return function (constructor, locals) {
        var controller = $delegate.apply(null, arguments);

        return angular.extend(function () {
            locals.$scope.common = ...;
            return controller();
        }, controller);
    };
});


回答2:

Answering my own question.

Had to dig in to Angular source code to figure out whats going on.

The $controller instance is created using below code. The fix lay in the parameter 'later'. This needs to be set to true.

    return function(expression, locals, later, ident) {
      // PRIVATE API:
      //   param `later` --- indicates that the controller's constructor is invoked at a later time.
      //                     If true, $controller will allocate the object with the correct
      //                     prototype chain, but will not invoke the controller until a returned
      //                     callback is invoked.

Above taken from: https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.js

Updated provider code:

angular.module('myApp', ['ng'], function($provide) {
    $provide.decorator('$controller', function($delegate) {

 return function(constructor, locals) {

            //Custom behaviour code

            return $delegate(constructor, locals, true);
        }
    })
});

Updated fiddle: http://jsfiddle.net/v3067u98/1/