编辑:我设法让我的单元测试运行 - 我将包含服务的代码移动到另一个文件和一个不同的模块,使这个新模块成为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
中,那么应用程序和单元测试将再次开始工作。但是我不能将它们包含在同一个文件中 - 如何在不破坏应用程序和单元测试的情况下在角度范围内运行它?
答案 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.js
和controllers.js
之类的设置:
在app.js中,定义模块范围:
var myApp = angular.module(<module_name>, [<dependencies>]);
在controllers.js中,不要再次定义myApp - 而是直接使用它,如:
myApp.controller(..);
这就是诀窍 - 我的应用程序和单元测试现在正常工作!
答案 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中收到类似的错误。