Inyectar servicio en app.config

Quiero inyectar un servicio en app.config, para que los datos puedan recuperarse antes de que se llame al controlador. Lo intenté así:

Servicio:

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

Pero me sale este error:

Error: proveedor desconocido: dbService de EditorApp

¿Cómo corregir la configuración e inyectar este servicio?

Alex proporcionó la razón correcta para no poder hacer lo que estás tratando de hacer, así que +1. Pero te encuentras con este problema porque no estás usando resuelve cómo están diseñados.

resolve toma la cadena de un servicio o una función que devuelve un valor para ser inyectado. Como estás haciendo lo último, debes pasar una función real:

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

Cuando el marco va a resolver los data , inyectará el dbService en la función para que pueda usarlo libremente. No necesita inyectar nada en el bloque de config para lograr esto.

¡Buen provecho!

Configure su servicio como un proveedor AngularJS personalizado

A pesar de lo que dice la respuesta Aceptada, en realidad PUEDE hacer lo que tenía la intención de hacer, pero debe configurarlo como un proveedor configurable, de modo que esté disponible como un servicio durante la fase de configuración. Primero, cambie su Service a un proveedor como se muestra a continuación. La diferencia clave aquí es que después de establecer el valor de defer , establece la propiedad defer.promise al objeto promesa devuelto por $http.get :

Servicio del proveedor: (proveedor: receta del servicio)

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

Ahora, tiene un proveedor personalizado configurable, solo necesita inyectarlo. La diferencia clave aquí es la falta de “Proveedor de su inyectable”.

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

usa datos resueltos en tu 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 posibles

La siguiente alternativa es un enfoque similar, pero permite la definición dentro de .config , encapsulando el servicio dentro del módulo específico en el contexto de su aplicación. Elija el método más adecuado para usted. También vea a continuación las notas sobre una tercera alternativa y enlaces útiles para ayudarlo a entender todas estas cosas

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

Algunos recursos útiles

  • John Lindquist tiene una excelente explicación de 5 minutos y una demostración de esto en egghead.io , ¡y es una de las lecciones gratuitas! Básicamente modifiqué su demostración haciéndola $http específica en el contexto de esta solicitud
  • Ver la guía para desarrolladores de AngularJS sobre Proveedores
  • También hay una excelente explicación sobre factory / service / provider en clevertech.biz .

El proveedor le da un poco más de configuración sobre el método .service , que lo hace mejor como un proveedor de nivel de aplicación, pero también podría encapsular esto dentro del objeto config inyectando $provide into config de esta manera:

Respuesta corta: no puedes. AngularJS no le permitirá inyectar servicios en la configuración porque no puede estar seguro de que se hayan cargado correctamente.

Vea esta pregunta y respuesta: inyección de valor de dependencia AngularJS dentro de module.config

Un módulo es una colección de bloques de configuración y ejecución que se aplican a la aplicación durante el proceso de arranque. En su forma más simple, el módulo consiste en una colección de dos tipos de bloques:

Bloques de configuración : se ejecutan durante los registros del proveedor y la fase de configuración. Solo proveedores y constantes se pueden inyectar en bloques de configuración. Esto es para evitar la instanciación accidental de servicios antes de que se hayan configurado completamente.

No creo que se suponga que puedas hacer esto, pero he inyectado con éxito un servicio en un bloque 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(); } }); }; } ]); 

** Solicita explícitamente servicios de otros módulos usando angular.injector **

Para elaborar la respuesta de kim3er , puede proporcionar servicios, fábricas, etc. sin cambiarlos a proveedores, siempre que estén incluidos en otros módulos …

Sin embargo, no estoy seguro de si el *Provider (que se hace internamente por angular después de procesar un servicio, o de fábrica) siempre estará disponible (puede depender de qué otro se cargue primero), ya que angularmente carga módulos de forma perezosa.

Tenga en cuenta que si desea reinyectar los valores, deben tratarse como constantes.

Aquí hay una manera más explícita, y probablemente más confiable de hacerlo + un plunker de trabajo

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

Puede usar el servicio $ inject para inyectar un servicio en su configuración

 app.config (function ($ provide) {

     $ provide.decorator ("$ exceptionHandler", función ($ delegate, $ injector) {
         función de retorno (excepción, causa) {
             var $ rootScope = $ injector.get ("$ rootScope");
             $ rootScope.addError ({mensaje: "Excepción", razón: excepción});
             $ delegado (excepción, causa);
         };
     });

 });

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

Usando $ injector para llamar a los métodos de servicio en config

Tuve un problema similar y lo resolví utilizando el servicio $ injector como se muestra arriba. Intenté inyectar el servicio directamente pero terminé con una dependencia circular en $ http. El servicio muestra un modal con el error y estoy usando ui-bootstrap modal, que también tiene una dependencia en $ 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.") } } } 

Una solución muy fácil de hacer

Nota : es solo para una llamada asynchrone, porque el servicio no se inicializa en la ejecución de la configuración.

Puede usar el método run() . Ejemplo:

  1. Su servicio se llama “MyService”
  2. Desea usarlo para una ejecución asynchrone en un proveedor “MyProvider”

Tu codigo :

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

La manera más fácil: $injector = angular.element(document.body).injector()

Luego, use eso para ejecutar invoke() o get()

Bueno, luché un poco con esto, pero en realidad lo hice.

No sé si las respuestas están desactualizadas debido a algún cambio en angular, pero puedes hacerlo de esta manera:

Este es su servicio:

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

Y esta es la configuración

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