- Windows10
- Bash
Black Sand Solutions
Using ng-strict-di to Debug AngularJS Unknown Provider Error
- AngularJS
Angular is awesome; but sometimes it can be difficult to decipher error messages it raises, particularly when you are just starting out.
Using ng-strict-di to Debug AngularJS Unknown Provider Error - Or, How to fix a missing $injector error
A common error for the newbie and sometimes even the seasoned pro is the Unknown Provider, or $injector error. I know I fell foul of this a lot in my early days - And normally, after the site was deployed.
Here is the typical error message and associated output in the console.
Error An error has occurred. Please try again. Error: [$injector:strictdi] > http://errors.angularjs.org/1.3.16/$injector/strictdi?p0=function(n%2Ct)
Ng-Strict-Di
The easiest way to debug these errors is to catch them before the code is minified - i.e. during development. As of Angular 1.3 there is a directive called ng-strict-di which will help you find these issues.
From the documenation:
if this attribute is present on the app element, the injector will be created in "strict-di" mode. This means that the application will fail to invoke functions which do not use explicit function annotation (and are thus unsuitable for minification), as described in the Dependency Injection guide, and useful debugging info will assist in tracking down the root of these bugs.
Using this directive is simple. Add it where you declare your app.
<div ng-app="some-angular-app" ng-strict-di="">
...
</div>
Then, when you forget to inject your dependencies you'll now get an error like this:
Error: [$injector:strictdi] function($scope, > $stateParams) is not using explicit annotation and cannot be invoked in strict mode
http://errors.angularjs.org/1.3.16/$injector/strictdi?p0=function(%24scope%2C %24stateParams)
Correcting Some Typical Scenarios
OK, so you forgotten to inject your dependencies, how do you resolve this?
Some common scenarios are shown below.
Controller
Probably the most common scenario, or at least the first time you are likely to see this.
angular.module('app')
.controller('AppController', AppController);
function AppController($rootScope, $scope, AppService)
{
}
You can prevent these errors by using the either the array notation or explicit injection. Both can be applied to controllers, services and directives alike.
My personal preference is the explicit injection which I found easier to read and follows John Papa's StyleGuide. If you have not read this yet I strongly recommend you do.
/// array notation
angular.module('app')
.controller('AppController', ['$rootScope', '$scope', '$AppService',
function AppController($rootScope, $scope, AppService){
... controller code here ...
}]);
/// explicit injection
angular.module('app')
.controller('AppController', AppController);
AppController.$inject = ['$rootScope', '$scope', '$AppService'];
function AppController($rootScope, $scope, AppService)
{
... controller code here ...
}
UIRouter State Controller
The following code will generate the $inject error.
$stateProvider
.state('someState', {
templateUrl: '/someTemplate',
controller: function ($scope, $stateParams) {
$scope.imagePath = $stateParams.param;
}
})
This can be resolved either by using the array notation.
$stateProvider
.state('someState', {
templateUrl: '/someTemplate',
controller: ['$scope', '$stateParams', function($scope, $stateParams){
$scope.imagePath = $stateParams.param;
}
]}
})
UIRouter State Resolve
Similarly this use of the state's resolve property will raise the error.
$stateProvider
.state('someState', {
templateUrl: '/someTemplate',
controller: someController,
resolve: {
someDependency: function(someService){
return someService.getData();
}
};
}
})
Again, use array notation to solve.
$stateProvider
.state('someState', {
templateUrl: '/someTemplate',
controller: someController,
{
someDependency: ['someService', function(someService){
return someService.getData();
}
]}
})
Alternatively
An alternative approach is to not worry about this and simply let your build tools sort it out.
If you are using Grunt or Gulp it might be worth looking at ng-annotate. This task will:
add and remove AngularJS dependency injection annotations. It is non-intrusive so your source code stays exactly the same otherwise. No lost comments or moved lines. Annotations are useful because with them you're able to minify your source code using your favorite JS minifier.
https://www.npmjs.com/package/ng-annotate