我想在app.config中注入一个服务,以便在调用控制器之前检索数据。我试过这样的话:
服务:
app.service('dbService', function() {
return {
getData: function($q, $http) {
var defer = $q.defer();
$http.get('db.php/score/getData').success(function(data) {
defer.resolve(data);
});
return defer.promise;
}
};
});
配置:
app.config(function ($routeProvider, dbService) {
$routeProvider
.when('/',
{
templateUrl: "partials/editor.html",
controller: "AppCtrl",
resolve: {
data: dbService.getData(),
}
})
});
但是我收到了这个错误:
错误:来自EditorApp的未知提供程序:dbService
如何更正设置并注入此服务?
答案 0 :(得分:138)
尽管接受的答案是什么,但实际上 CAN 执行您打算做的事情,但您需要将其设置为可配置的提供程序,以便在配置期间将其作为服务提供阶段..首先,将您的Service
更改为提供者,如下所示。这里的关键区别是,在设置defer
的值之后,将defer.promise
属性设置为$http.get
返回的promise对象:
提供商服务:(提供商:服务配方)
app.provider('dbService', function dbServiceProvider() {
//the provider recipe for services require you specify a $get function
this.$get= ['dbhost',function dbServiceFactory(dbhost){
// return the factory as a provider
// that is available during the configuration phase
return new DbService(dbhost);
}]
});
function DbService(dbhost){
var status;
this.setUrl = function(url){
dbhost = url;
}
this.getData = function($http) {
return $http.get(dbhost+'db.php/score/getData')
.success(function(data){
// handle any special stuff here, I would suggest the following:
status = 'ok';
status.data = data;
})
.error(function(message){
status = 'error';
status.message = message;
})
.then(function(){
// now we return an object with data or information about error
// for special handling inside your application configuration
return status;
})
}
}
现在,您有一个可配置的自定义提供程序,您只需要注入它。这里的关键区别是缺少“注射剂供应商”。
配置:
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: "partials/editor.html",
controller: "AppCtrl",
resolve: {
dbData: function(DbService, $http) {
/*
*dbServiceProvider returns a dbService instance to your app whenever
* needed, and this instance is setup internally with a promise,
* so you don't need to worry about $q and all that
*/
return DbService('http://dbhost.com').getData();
}
}
})
});
在appCtrl
app.controller('appCtrl',function(dbData, DbService){
$scope.dbData = dbData;
// You can also create and use another instance of the dbService here...
// to do whatever you programmed it to do, by adding functions inside the
// constructor DbService(), the following assumes you added
// a rmUser(userObj) function in the factory
$scope.removeDbUser = function(user){
DbService.rmUser(user);
}
})
以下替代方法是类似的方法,但允许在.config
内进行定义,将服务封装在应用程序上下文中的特定模块中。选择适合您的方法。另请参阅下面的第3个备选和有用链接的说明,以帮助您掌握所有这些内容
app.config(function($routeProvider, $provide) {
$provide.service('dbService',function(){})
//set up your service inside the module's config.
$routeProvider
.when('/', {
templateUrl: "partials/editor.html",
controller: "AppCtrl",
resolve: {
data:
}
})
});
$http
具体来修改他的演示factory
/ service
/ provider
at clevertech.biz还有一个很好的解释。提供程序为您提供了比.service
方法更多的配置,这使其更好地作为应用程序级提供程序,但您也可以通过将$provide
注入到配置中来将其封装在配置对象本身中像这样:
答案 1 :(得分:127)
亚历克斯提供了无法做你想做的事的正确理由,所以+1。但是你遇到了这个问题,因为你并没有完全按照它们的设计使用它们。
resolve
接受服务的字符串或返回要注入的值的函数。既然你正在做后者,你需要传递一个实际的函数:
resolve: {
data: function (dbService) {
return dbService.getData();
}
}
当框架解析data
时,它会将dbService
注入函数中,以便您可以自由使用它。您根本不需要注入config
块来完成此任务。
Bon appetit!
答案 2 :(得分:20)
简短的回答:你做不到。 AngularJS不允许您将服务注入到配置中,因为它无法确定它们是否已正确加载。
看到这个问题和答案: AngularJS dependency injection of value inside of module.config
模块是配置和运行块的集合 在引导过程中应用于应用程序。在其中 最简单的形式模块由两种块的集合组成:
配置块 - 在提供商注册和配置阶段执行。只有提供者和常量 可以注入配置块。这是为了防止 在服务完全之前意外实例化服务 构造
答案 3 :(得分:5)
我认为您不应该这样做,但我已成功将服务注入config
块。 (AngularJS v1.0.7)
angular.module('dogmaService', [])
.factory('dogmaCacheBuster', [
function() {
return function(path) {
return path + '?_=' + Date.now();
};
}
]);
angular.module('touch', [
'dogmaForm',
'dogmaValidate',
'dogmaPresentation',
'dogmaController',
'dogmaService',
])
.config([
'$routeProvider',
'dogmaCacheBusterProvider',
function($routeProvider, cacheBuster) {
var bust = cacheBuster.$get[0]();
$routeProvider
.when('/', {
templateUrl: bust('touch/customer'),
controller: 'CustomerCtrl'
})
.when('/screen2', {
templateUrl: bust('touch/screen2'),
controller: 'Screen2Ctrl'
})
.otherwise({
redirectTo: bust('/')
});
}
]);
angular.module('dogmaController', [])
.controller('CustomerCtrl', [
'$scope',
'$http',
'$location',
'dogmaCacheBuster',
function($scope, $http, $location, cacheBuster) {
$scope.submit = function() {
$.ajax({
url: cacheBuster('/customers'), //server script to process data
type: 'POST',
//Ajax events
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false,
success: function() {
$location
.path('/screen2');
$scope.$$phase || $scope.$apply();
}
});
};
}
]);
答案 4 :(得分:5)
**使用angular.injector **
显式请求来自其他模块的服务只是详细说明kim3er's answer,您可以提供服务,工厂等,而无需将其更改为提供者,只要它们包含在其他模块中......
但是,我不确定*Provider
(在处理服务或工厂后由角度内部制作)是否始终可用(它可能取决于首先加载的其他内容),因为角度懒惰地加载模块。
请注意,如果要重新注入应将它们视为常量的值。
这是一个更明确,更可靠的方法+ a working plunker
var base = angular.module('myAppBaseModule', [])
base.factory('Foo', function() {
console.log("Foo");
var Foo = function(name) { this.name = name; };
Foo.prototype.hello = function() {
return "Hello from factory instance " + this.name;
}
return Foo;
})
base.service('serviceFoo', function() {
this.hello = function() {
return "Service says hello";
}
return this;
});
var app = angular.module('appModule', []);
app.config(function($provide) {
var base = angular.injector(['myAppBaseModule']);
$provide.constant('Foo', base.get('Foo'));
$provide.constant('serviceFoo', base.get('serviceFoo'));
});
app.controller('appCtrl', function($scope, Foo, serviceFoo) {
$scope.appHello = (new Foo("app")).hello();
$scope.serviceHello = serviceFoo.hello();
});
答案 5 :(得分:4)
您可以使用$ inject服务在您的配置中注入服务
app.config(function($provide){ $provide.decorator("$exceptionHandler", function($delegate, $injector){ return function(exception, cause){ var $rootScope = $injector.get("$rootScope"); $rootScope.addError({message:"Exception", reason:exception}); $delegate(exception, cause); }; }); });
来源:http://odetocode.com/blogs/scott/archive/2014/04/21/better-error-handling-in-angularjs.aspx
答案 6 :(得分:2)
使用$ injector调用config
中的服务方法我有一个类似的问题并通过使用$ injector服务解决了它,如上所示。我尝试直接注入服务,但结果是对$ http的循环依赖。该服务显示一个带有错误的模态,我使用的是ui-bootstrap模式,它也依赖于$ https。
$httpProvider.interceptors.push(function($injector) {
return {
"responseError": function(response) {
console.log("Error Response status: " + response.status);
if (response.status === 0) {
var myService= $injector.get("myService");
myService.showError("An unexpected error occurred. Please refresh the page.")
}
}
}
答案 7 :(得分:1)
解决方案非常容易
注意:它仅用于asynchrone调用,因为在配置执行时未初始化服务。
您可以使用run()
方法。示例:
您的代码:
(function () { //To isolate code TO NEVER HAVE A GLOBAL VARIABLE!
//Store your service into an internal variable
//It's an internal variable because you have wrapped this code with a (function () { --- })();
var theServiceToInject = null;
//Declare your application
var myApp = angular.module("MyApplication", []);
//Set configuration
myApp.config(['MyProvider', function (MyProvider) {
MyProvider.callMyMethod(function () {
theServiceToInject.methodOnService();
});
}]);
//When application is initialized inject your service
myApp.run(['MyService', function (MyService) {
theServiceToInject = MyService;
}]);
});
答案 8 :(得分:0)
最简单的方法:
$injector = angular.element(document.body).injector()
然后使用它来运行invoke()
或get()
答案 9 :(得分:0)
嗯,我在这个问题上有点挣扎,但实际上我做到了。
我不知道由于角度的某些变化,答案是否已经过时,但你可以这样做:
这是您的服务:
.factory('beerRetrievalService', function ($http, $q, $log) {
return {
getRandomBeer: function() {
var deferred = $q.defer();
var beer = {};
$http.post('beer-detail', {})
.then(function(response) {
beer.beerDetail = response.data;
},
function(err) {
$log.error('Error getting random beer', err);
deferred.reject({});
});
return deferred.promise;
}
};
});
这是配置
.when('/beer-detail', {
templateUrl : '/beer-detail',
controller : 'productDetailController',
resolve: {
beer: function(beerRetrievalService) {
return beerRetrievalService.getRandomBeer();
}
}
})