AngularJs版本升级项目build后报错Error: [$injector:unpr] Unknown provider: e

错误提示:

Uncaught Error: [$injector:modulerr] Failed to instantiate module mulan due to:
Error: [$injector:modulerr] Failed to instantiate module login due to:
Error: [$injector:unpr] Unknown provider: e

原因是因为AngularJs升级了,现有项目是meteor的build后提示这个错误,是因为angular声明module的时候需要用array数组声明$stateProvider,这样build后就能初始化module了

修改方法:

报错代码:

export default angular.module(‘member’, [
angularMeteor,
uiRouter,
‘header_search’,
])
.config(function ($stateProvider) { //这么声明老版本的支持,新版本不支持了
‘ngInject’;

。。。。

});

修改后的代码:

export default angular.module(‘member’, [
angularMeteor,
uiRouter,
‘header_search’,
])
.config([‘$stateProvider’,function ($stateProvider) {
‘ngInject’;

。。。。

]});

引申问题:Controller的声明也需要按数组式声明,官方文档参考:

https://docs.angularjs.org/guide/di#dependency-annotation

Using Dependency Injection

Dependency Injection is pervasive throughout AngularJS. You can use it when defining components or when providing run and config blocks for a module.

  • Servicesdirectivesfilters, and animations are defined by an injectable factory method or constructor function, and can be injected with “services”, “values”, and “constants” as dependencies.
  • Controllers are defined by a constructor function, which can be injected with any of the “service” and “value” as dependencies, but they can also be provided with “special dependencies”. See Controllers below for a list of these special dependencies.
  • The run method accepts a function, which can be injected with “services”, “values” and, “constants” as dependencies. Note that you cannot inject “providers” into run blocks.
  • The config method accepts a function, which can be injected with “providers” and “constants” as dependencies. Note that you cannot inject “services” or “values” into configuration.
  • The provider method can only be injected with other “providers”. However, only those that have been registered beforehand can be injected. This is different from services, where the order of registration does not matter.

See Modules for more details about run and config blocks and Providers for more information about the different provider types.

Factory Methods

The way you define a directive, service, or filter is with a factory function. The factory methods are registered with modules. The recommended way of declaring factories is:

angular.module('myModule', [])
.factory('serviceId', ['depService', function(depService) {
  // ...
}])
.directive('directiveName', ['depService', function(depService) {
  // ...
}])
.filter('filterName', ['depService', function(depService) {
  // ...
}]);

Module Methods

We can specify functions to run at configuration and run time for a module by calling the config and run methods. These functions are injectable with dependencies just like the factory functions above.

angular.module('myModule', [])
.config(['depProvider', function(depProvider) {
  // ...
}])
.run(['depService', function(depService) {
  // ...
}]);

Controllers

Controllers are “classes” or “constructor functions” that are responsible for providing the application behavior that supports the declarative markup in the template. The recommended way of declaring Controllers is using the array notation:

someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
}]);

Unlike services, there can be many instances of the same type of controller in an application.

Moreover, additional dependencies are made available to Controllers:

  • $scope: Controllers are associated with an element in the DOM and so are provided with access to the scope. Other components (like services) only have access to the $rootScope service.
  • resolves: If a controller is instantiated as part of a route, then any values that are resolved as part of the route are made available for injection into the controller.

Dependency Annotation

AngularJS invokes certain functions (like service factories and controllers) via the injector. You need to annotate these functions so that the injector knows what services to inject into the function. There are three ways of annotating your code with service name information:

  • Using the inline array annotation (preferred)
  • Using the $inject property annotation
  • Implicitly from the function parameter names (has caveats)

Inline Array Annotation

This is the preferred way to annotate application components. This is how the examples in the documentation are written.

For example:

someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
  // ...
}]);

Here we pass an array whose elements consist of a list of strings (the names of the dependencies) followed by the function itself.

When using this type of annotation, take care to keep the annotation array in sync with the parameters in the function declaration.

$inject Property Annotation

To allow the minifiers to rename the function parameters and still be able to inject the right services, the function needs to be annotated with the $inject property. The $inject property is an array of service names to inject.

var MyController = function($scope, greeter) {
  // ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);

In this scenario the ordering of the values in the $inject array must match the ordering of the parameters in MyController.

Just like with the array annotation, you’ll need to take care to keep the $inject in sync with the parameters in the function declaration.

Implicit Annotation

Careful: If you plan to minify your code, your service names will get renamed and break your app.

The simplest way to get hold of the dependencies is to assume that the function parameter names are the names of the dependencies.

someModule.controller('MyController', function($scope, greeter) {
  // ...
});

Given a function, the injector can infer the names of the services to inject by examining the function declaration and extracting the parameter names. In the above example, $scope and greeter are two services which need to be injected into the function.

One advantage of this approach is that there’s no array of names to keep in sync with the function parameters. You can also freely reorder dependencies.

However this method will not work with JavaScript minifiers/obfuscators because of how they rename parameters.

Tools like ng-annotate let you use implicit dependency annotations in your app and automatically add inline array annotations prior to minifying. If you decide to take this approach, you probably want to use ng-strict-di.

Because of these caveats, we recommend avoiding this style of annotation.

参考资料:

https://www.blacksandsolutions.co/blog/posts/debug-unknown-provider-error-with-ng-strict/

https://github.com/brandon-barker/angular-floatThead/issues/14

https://stackoverflow.com/questions/32467677/angularjs-debugging-of-injectorunpr-unknown-provider-e

https://docs.angularjs.org/guide/di#dependency-annotation

https://segmentfault.com/q/1010000005020067

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏