Injetar serviço no app.config

Eu quero injetar um serviço em app.config, para que os dados possam ser recuperados antes que o controlador seja chamado. Eu tentei assim:

Serviço:

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

Config:

 app.config(function ($routeProvider, dbService) { $routeProvider .when('/', { templateUrl: "partials/editor.html", controller: "AppCtrl", resolve: { data: dbService.getData(), } }) }); 

Mas eu recebo este erro:

Erro: provedor desconhecido: dbService from EditorApp

Como corrigir a configuração e injetar este serviço?

Alex forneceu o motivo correto para não ser capaz de fazer o que você está tentando fazer, portanto, +1. Mas você está encontrando esse problema porque você não está usando bastante resolve como eles são projetados.

resolve leva a string de um serviço ou uma function retornando um valor a ser injetado. Desde que você está fazendo o último, você precisa passar em uma function real:

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

Quando o framework for para resolver data , ele irá injetar o dbService na function para que você possa usá-lo livremente. Você não precisa injetar no bloco de config para realizar isso.

Bom apetite!

Configure seu serviço como um provedor personalizado do AngularJS

Apesar do que a resposta aceita diz, você realmente pode fazer o que você pretende fazer, mas você precisa configurá-lo como um provedor configurável, para que ele esteja disponível como um serviço durante a fase de configuração. Primeiro, mude seu Service para um provedor, como mostrado abaixo. A principal diferença aqui é que, depois de definir o valor de defer.promise , você define a propriedade defer.promise como o object de promise retornado por $http.get :

Serviço de Provedor: (provedor: receita de serviço)

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

Agora, você tem um provedor personalizado configurável, você só precisa injetá-lo. A principal diferença aqui é a falta do “Provedor no seu injetável”.

config:

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

usar dados resolvidos no seu 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); } }) 

Alternativas possíveis

A alternativa a seguir é uma abordagem semelhante, mas permite que a definição ocorra dentro do .config , encapsulando o serviço dentro do módulo específico no contexto do seu aplicativo. Escolha o método certo para você. Veja também abaixo as notas em um terceiro link alternativo e útil para ajudá-lo a pegar o jeito de todas essas coisas

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

Alguns resources úteis

  • John Lindquist tem uma excelente explicação de 5 minutos e demonstração disso em egghead.io , e é uma das lições gratuitas! Eu basicamente modifiquei sua demonstração, tornando $http específico no contexto desta solicitação
  • Veja o guia do AngularJS para desenvolvedores em Providers
  • Há também uma excelente explicação sobre factory / service / provider em clevertech.biz .

O provedor lhe dá um pouco mais de configuração sobre o método .service , o que o torna melhor como um provedor de nível de aplicativo, mas você também pode encapsular isso dentro do próprio object de configuração, injetando $provide em config da seguinte forma:

Resposta curta: você não pode. O AngularJS não permitirá que você injete serviços na configuração porque não pode ter certeza de que eles foram carregados corretamente.

Veja esta pergunta e resposta: injeção de dependência AngularJS de valor dentro de module.config

Um módulo é uma coleção de blocos de configuração e execução que são aplicados ao aplicativo durante o processo de bootstrap. Em sua forma mais simples, o módulo consiste na coleta de dois tipos de blocos:

Blocos de configuração – são executados durante os registros do fornecedor e na fase de configuração. Somente provedores e constantes podem ser injetados nos blocos de configuração. Isso é para impedir a instanciação acidental de serviços antes que eles tenham sido totalmente configurados.

Eu não acho que você seja capaz de fazer isso, mas eu injetou com sucesso um serviço em um bloco de 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(); } }); }; } ]); 

** Explicitamente solicitar serviços de outros módulos usando angular.injector **

Apenas para elaborar a resposta do kim3er , você pode fornecer serviços, fábricas, etc sem alterá-los para provedores, contanto que eles estejam incluídos em outros módulos …

No entanto, não tenho certeza se o *Provider (que é feito internamente por angular depois de processar um serviço ou fábrica) estará sempre disponível (pode depender do que mais foi carregado primeiro), pois os módulos carregam os módulos com lentidão.

Observe que, se você quiser reinjetar os valores, eles devem ser tratados como constantes.

Aqui está uma maneira mais explícita e provavelmente mais confiável de fazê-lo + uma plunker de trabalho

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

Você pode usar o serviço $ inject para injetar um serviço na sua configuração

 app.config (function ($ fornecer) {

     $ prove.decorator ("$ exceptionHandler", function ($ delegate, $ injector) {
         function de retorno (exceção, causa) {
             var $ rootScope = $ injector.get ("$ rootScope");
             $ rootScope.addError ({message: "Exception", razão: exception});
             $ delegate (exceção, causa);
         };
     });

 });

Fonte: http://odetocode.com/blogs/scott/archive/2014/04/21/better-error-handling-in-angularjs.aspx

Usando $ injector para chamar methods de serviço na configuração

Eu tive um problema semelhante e resolvi usando o serviço $ injector como mostrado acima. Eu tentei injetar o serviço diretamente, mas acabei com uma dependência circular de $ http. O serviço exibe um modal com o erro e estou usando o modal ui-bootstrap, que também tem uma dependência de $ 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.") } } } 

Uma solução muito fácil de fazer

Nota : é apenas para uma chamada assíncrona, porque o serviço não é inicializado na execução de configuração.

Você pode usar o método run() . Exemplo:

  1. Seu serviço é chamado “MyService”
  2. Você deseja usá-lo para uma execução assíncrona em um provedor “MyProvider”

Seu código :

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

$injector = angular.element(document.body).injector() mais fácil: $injector = angular.element(document.body).injector()

Então use isso para executar invoke() ou get()

Bem, eu lutei um pouco com este, mas eu realmente fiz isso.

Eu não sei se as respostas estão desatualizadas por causa de alguma mudança na angular, mas você pode fazer assim:

Este é o seu serviço:

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

E esta é a configuração

 .when('/beer-detail', { templateUrl : '/beer-detail', controller : 'productDetailController', resolve: { beer: function(beerRetrievalService) { return beerRetrievalService.getRandomBeer(); } } })