AngularJS - 错误:未知提供者:searchResultsProvider

时间:2013-04-14 08:12:36

标签: angularjs karma-runner

编辑:我设法让我的单元测试运行 - 我将包含服务的代码移动到另一个文件和一个不同的模块,使这个新模块成为fooBar模块的要求,然后在每个“它之前” “调用块,引入代码beforeEach(module(<new_service_module_name))。但是,我的应用程序仍然无法运行。控制台也没有错误。这是唯一仍然存在的问题 - 当我使用全局范围进行控制器定义时,应用程序可以工作,但是当我使用angular.module.controller时 - 它没有。

我有一个文件app.js,其中包含以下内容:

'use strict';

var app = angular.module('fooBar', []);

app.config(['$routeProvider', function($routeProvider) {
  $routeProvider.
  when('/', {
    templateUrl: 'partials/form-view.html',
    controller: FormViewCtrl
  }).
  when('/resultDisplay', {
    templateUrl: 'partials/table-view.html',
    controller: TableViewCtrl
  }).
  otherwise({redirectTo: '/'});
}]);

app.service('searchResults', function() {
  var results = {};

  return {
    getResults: function() {
      return results;
    },
    setResults: function(resultData) {
      results = resultData;
    }
  };
});

我有另一个文件controllers.js,其中包含以下内容:

'use strict';

var app = angular.module('fooBar', []);

app.controller('FormViewCtrl', ['$scope', '$location', '$http', 'searchResults', 
    function ($scope, $location, $http, searchResults) {
        //Controller code
}]);

searchResults是我创建的一个只有getter和setter方法的服务。上面的控制器使用setter方法,因此服务被注入其中。

结果,我的应用程序没有运行! 如果我将控制器代码更改为全局,请执行以下操作:

function ($scope, $location, $http, searchResults) {
    //Controller code
}

然后应用程序正常工作!

此外,如果我使用全局范围,则以下单元测试用例可用:

'use strict';

/*jasmine specs for controllers go here*/
describe('Foo Bar', function() {

    describe('FormViewCtrl', function() {
        var scope, ctrl;

        beforeEach(module('fooBar'));

        beforeEach(inject(function($rootScope, $controller) {
            scope = $rootScope.$new();
            ctrl = $controller('FormViewCtrl', {$scope: scope});
        }));
        }
        //"it" blocks
}

如果我恢复到模块范围,我会收到错误 -
Error: Unknown provider: searchResultsProvider <- searchResults

因此,通过使用全局范围我的应用程序和单元测试运行但是通过使用app.controller,它们似乎会中断。

我注意到的另一点是,如果我将控制器代码包含在app.js而不是controllers.js中,那么应用程序和单元测试将再次开始工作。但是我不能将它们包含在同一个文件中 - 如何在不破坏应用程序和单元测试的情况下在角度范围内运行它?

4 个答案:

答案 0 :(得分:9)

你不需要走那条路。您可以使用模块化方法,但问题在于您的第二个参数。

在你的app.js中你有这个:

var app = angular.module('fooBar', []);

然后在你的控制器中,你有这个:

var app = angular.module('fooBar', []);

你在做什么是定义模块两次。如果您只是尝试附加到app模块,则无法传入第二个参数(空数组:[]),因为这会创建一个全新的模块,覆盖第一个参数。

以下是我的工作方式(基于this article来构建大型AngularJS应用程序。

app.js:

angular.module('fooBar',['fooBar.controllers', 'fooBar.services']);
angular.module('fooBar.controllers',[]);
angular.module('fooBar.services', []);
...etc

controllers.js

angular.module('foobar.controllers') // notice the lack of second parameter
    .controller('FormViewCtrl', function($scope) {
        //controller stuffs
    });

或者,对于非常大的项目,建议不要按类型(指令,过滤器,服务,控制器)对顶级模块进行分组,而是按功能(包括所有部分...)的原因进行分组是完全模块化的 - 您可以创建一个新模块,使用相同的名称,新的部分和代码,将其作为替代品放入您的项目中,并且它将简单地工作),例如

app.js

angular.module('fooBar',['fooBar.formView', 'fooBar.otherView']);
angular.module('fooBar.formView',[]);
angular.module('fooBar.otherView', []);
...etc

然后在挂在网络根目录下的formView文件夹中,您可以根据类型分离出您的文件,例如:

formView.directives
formView.controllers
formView.services
formView.filters

And then, in each of those files, you open with: 

angular.module('formView')
    .controller('formViewCtrl', function($scope) {

angular.module('formView')
    .factory('Service', function() {

etc etc

HTH

答案 1 :(得分:2)

好的 - 我终于明白了。基本上,如果您希望使用模块范围而不是全局范围,那么我们需要执行以下操作(如果您有app.jscontrollers.js之类的设置:

  1. 在app.js中,定义模块范围:

    var myApp = angular.module(<module_name>, [<dependencies>]);

  2. 在controllers.js中,不要再次定义myApp - 而是直接使用它,如:

    myApp.controller(..);

  3. 这就是诀窍 - 我的应用程序和单元测试现在正常工作!

答案 2 :(得分:1)

最佳做法是只有一个全局变量,您的应用并附加所有必需的模块功能,以便您的应用程序以

启动
var app = angular.module('app',[ /* Dependencies */ ]);

在你的controller.js中你再次将它发送到一个新变量中,丢失之前连接的所有服务和配置,只启动你的app变量一次,再次执行它会让你失去你附加的服务它

然后添加服务(工厂版)

app.factory('NewLogic',[ /* Dependencies */ , function(  /* Dependencies */ ) {
return {
function1: function(){
   /* function1 code */

    }
  }
}]);

用于控制器

app.controller('NewController',[ '$scope' /* Dependencies */ , function( $scope /* Dependencies */ ) {
$scope.function1 = function(){
   /* function1 code */
    };
  }
}]);

并且对于指令和配置也是类似的,您可以创建一个应用程序模块并将所有需要的控制器,指令和服务附加到它,但都包含在父应用程序模块变量中。

我已经一次又一次地读到,对于javascript,最好的做法是只有一个全局变量,所以angularjs架构真的很好地满足了这个要求,

哦,并且实际上并不需要依赖项的数组包装器,但如果你想缩小你的JS这么好的想法总是坚持最佳实践并且不做工作来获取,那么它将创建一堆全局变量并完全打破应用程序工作的事情

答案 3 :(得分:0)

就我而言,我已经定义了一个新的提供商,比如xyz

angular.module('test')
.provider('xyz', function () {
    ....
});

当您配置上述提供商时,您已为其注入了附加的“提供商”字符串。

例如:

angular.module('App', ['test'])
.config(function (xyzProvider) {
     // do something with xyzProvider....
});

如果您在没有'Provider'字符串的情况下注入上述提供者,您将在OP中收到类似的错误。