Define and run an arbitrary function that can have Angular services injected into it.

Versions used below

{
  "angular": "1.3.14",
  "ng-annotate": "0.15.4"
}

Why not just use closures?

The easy solution is using a closure to access dependencies instead of injecting them as parameters.

app.factory('myService', function(service1) {

  function func() {
    // service1 is available here
  }
});

In my case, the function was created in a module config block and passed to a provider to be invoked later. You can only inject providers and Angular constants into config blocks so the closure trick won’t work.

// DOES NOT WORK
app.config(function(service1) { // services don't exist during config phase so can't inject here

  function func() {

  }
});

The above results in error:

Error: [$injector:modulerr] Failed to instantiate module app due to:
[$injector:unpr] Unknown provider: service1

Using $injector

Angular makes this pretty easy. Use $injector to invoke the function.

$injector.invoke(func);

$injector.invoke invokes func with all its dependencies as parameters and returns func’s return value.

func must follow one of the three Angular “injectable function” patterns:

1. inferred

Note: this style won’t work if the code is minified

function func(dep1, dep2) {

}

2. inline

['dep1', 'dep2', function func(dep1, dep2) {

}]

3. annotated

function func(dep1, dep2) {

}

func.$inject = ['dep1', 'dep2']

ng-annotate compatibility

This injection can happen anywhere. It’s not in the Angular API like all other injections we’re used to. Will ng-annotate still see it?

The answer is… maybe.

There is only so much ng-annotate can detect through static code analysis. It has options for explicitly marking code to be annotated but at that point you might as well just annotate the code yourself.