Can the Angular $injector be decorated with $provide.decorator?

前端 未结 2 1215
闹比i
闹比i 2020-12-30 02:13

Perhaps this is a terrible idea, but if it is then please tell me why and then pretend that it\'s an academic exercise that won\'t see the light of day in production.

2条回答
  •  [愿得一人]
    2020-12-30 03:04

    You can't use the Angular decorator service on $injector. As Artur notes $injector is a bit different from other services. But we can create our own decorator.

    Why we can't use Angular's decorator

    At the code level the issue is that $injector doesn't have a constructor function- there's no $injectorProvider.

    For example both of these return true:

    $injector.has('$location');
    $injector.has('$locationProvider') 
    

    However, while this returns true:

    $injector.has('$injector')
    

    this returns false:

    $injector.has('$injectorProvider')
    

    We see the importance when we look at the Angular decorator function:

    function decorator(serviceName, decorFn) {
       var origProvider = providerInjector.get(serviceName + providerSuffix),
           orig$get = origProvider.$get;
    
       origProvider.$get = function() {
          var origInstance = instanceInjector.invoke(orig$get, origProvider);
         return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
       };
    }
    

    And

    providerSuffix = 'Provider'
    

    So the Angular decorator expects to operate on the service's constructor (serviceName + providerSuffix). Pragmatically, since we don't have an $injectorProvider we can't use decorator.

    Solution

    What we can do is override the Angular injector's get function ourselves by replacing the injector's default get with one that calls the original, Angular defined, get followed by our function.

    We'll apply this to $injector rather than the nonexistent $injectorProvider like so:

    app.config(['$provide','$injector', function ($provide,$injector) {
    
        // The function we'll add to the injector
        myFunc = function () {
            console.log("injector called ", arguments);
        };
    
        // Get a copy of the injector's get function
        var origProvider = $injector,
            origGet = origProvider.get;
    
        //Override injector's get with our own
        origProvider.get = function() {
    
            // Call the original get function 
            var returnValue = origGet.apply(this, arguments);
    
            // Call our function
            myFunc.apply(this,arguments);
    
            return returnValue;
        }
    }]);
    

    You'll see the provider being injected is the first augment, so app.value('aValue', 'something'); yields the following log statement:

    injector called  ["aValueProvider"]
    

    Demo fiddle

提交回复
热议问题