在 app.config 中注入服务

我想在 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

如何正确设置和注入此服务?

131124 次浏览

简而言之,你不能。AngularJS 不允许将服务注入到配置中,因为它无法确定服务是否已经正确加载。

看看这个问题和答案: Module.config 中的 AngularJS 值依赖注入

模块是配置块和运行块的集合,它们获取 在引导过程中应用到应用程序 最简单的模块由两种模块组成:

配置块 -在提供程序注册和配置阶段执行 可以注入到配置块中。这是为了防止 在服务完全实例化之前偶然实例化服务 配置好了。

Alex 给出了不能做你想做的事的正确理由,所以 + 1。但是您遇到了这个问题,因为您没有完全使用解决方案的设计方式。

resolve接受服务的字符串或返回要注入的值的函数。因为是后者,所以需要传入一个实际的函数:

resolve: {
data: function (dbService) {
return dbService.getData();
}
}

当框架解析 data时,它会将 dbService注入到函数中,这样您就可以自由使用它了。您根本不需要注入 config块来完成这个任务。

祝你好胃口!

我不认为你应该能够做到这一点,但我已经成功地注入一个服务到一个 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();
}
});
};
}
]);

将您的服务设置为自定义 AngularJS 提供程序

不管 Accepted 的答案是什么,实际上 可以做的是您想要做的事情,但是您需要将它设置为可配置的提供者,以便在配置阶段作为服务提供。.首先,将 Service更改为提供程序,如下所示。这里的关键区别在于,在设置了 defer的值之后,您将 defer.promise属性设置为由 $http.get返回的諾对象:

提供者服务: (提供者: 服务配方)

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中进行定义,将服务封装到应用程序上下文中的特定模块中。选择适合你的方法。也可以看看下面关于第三种选择的说明和有用的链接,帮助你掌握所有这些东西的窍门

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:
}
})
});

一些有用的资源

  • 约翰林奎斯特有一个很好的5分钟的解释和示范在 书呆子,我,这是一个免费的课程!我基本上修改了他的演示,在这个请求的上下文中将其特定于 $http
  • 供应商上查看 AngularJS 开发人员指南
  • 对于 factory/service/provider 在 Clevertech.biz也有很好的解释。

.service方法相比,提供程序为您提供了更多的配置,这使它更适合作为应用程序级提供程序,但是您也可以通过将 $provide注入到配置中来将其封装在配置对象本身中,如下所示:

* * 使用 angular.injector 显式地从其他模块请求服务 * *

只是详细说明 Kim3er 的回答,您可以提供服务,工厂等,而不改变他们的供应商,只要他们包括在其他模块..。

然而,我不确定 *Provider(在它处理服务或工厂之后通过角度在内部生成)是否总是可用(这可能取决于首先加载的是什么) ,因为角度延迟加载模块。

请注意,如果要重新注入值,则应将它们视为常量。

这里有一个更明确,可能更可靠的方法来做到这一点 + 工作的活塞

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();
});

使用 $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.")
}
}
}

一个非常简单的解决方案

注意 : 它仅用于异步调用,因为服务在配置执行时没有初始化。

你可以使用 run()方法。例如:

  1. 你的服务叫做“我的服务”
  2. 您希望将其用于提供程序“ MyProvider”上的异步执行

你的代码:

(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;
}]);
});

可以使用 $register 服务在配置中注入服务

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

最简单的方法: $injector = angular.element (document.body) . injector ()

然后用它来运行 invoke()get()

这次我有点纠结,但我真的做到了。

我不知道这些答案是否因为角度的变化而过时,但你可以这样做:

这是你的服务:

.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();
}
}
})