Ввести услугу в 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;
        }
    };
});

Config:

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

Но я получаю эту ошибку:

Ошибка: Неизвестный поставщик: dbService from EditorApp

Как исправить установку и ввести эту услугу?

Ответ 1

Алекс дал правильную причину неспособности делать то, что вы пытаетесь сделать, поэтому +1. Но вы столкнулись с этой проблемой, потому что вы не совсем используете решения, как они разработаны.

resolve принимает либо строку службы, либо функцию, возвращающую значение, которое нужно ввести. Поскольку вы делаете последнее, вам нужно передать фактическую функцию:

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

Когда инфраструктура переходит к решению data, она вводит dbService в функцию, чтобы вы могли свободно ее использовать. Вам не нужно вводить в блок config вообще, чтобы выполнить это.

Приятного аппетита!

Ответ 2

Настройте службу как пользовательский провайдер AngularJS

Несмотря на то, что говорит принятый ответ, вы действительно CAN выполняете то, что собираетесь намереваться, но вам нужно настроить его как настраиваемый провайдер, чтобы он был доступен как услуга во время конфигурации фаза. Сначала измените 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 config.

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

Несколько полезных ресурсов

  • Джон Линдквист имеет отличное 5-минутное объяснение и демонстрацию этого на egghead.io, и это один из бесплатных уроков! Я в основном изменил его демонстрацию, сделав его $http конкретным в контексте этого запроса.
  • Посмотрите руководство разработчика AngularJS на Providers
  • Существует также отличное объяснение factory/Service/provider на clevertech.biz.

Поставщик дает вам немного больше конфигурации по методу .service, что делает его лучше как поставщика уровня приложения, но вы также можете инкапсулировать его внутри самого объекта конфигурации, введя $provide в конфигурацию следующим образом:

Ответ 3

Короткий ответ: вы не можете. AngularJS не позволит вам вводить службы в конфигурацию, потому что не может быть уверен, что они были загружены правильно.

Смотрите этот вопрос и ответ: Угловая зависимость значения внутри модуля module.config

Модуль представляет собой набор конфигураций и блоков запуска, которые получают применяется к приложению во время процесса начальной загрузки. В своем Простейшая форма модуля состоит из набора двух видов блоков:

Блоки конфигурации - выполняются во время регистрации и конфигурации поставщика. Только поставщики и константы могут быть введены в конфигурационные блоки. Это необходимо для предотвращения случайное предоставление услуг до того, как они были полностью сконфигурирован.

Ответ 4

Я не думаю, что вы должны это сделать, но я успешно ввел службу в блок 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();
                    }
                });
            };
        }
    ]);

Ответ 5

Явно запрашиваю службы из других модулей с помощью anuglar.injector

Чтобы уточнить ответ kim3er, вы можете предоставлять сервисы, фабрики и т.д., не меняя их на поставщиков, если они включены в другие модули.

Однако я не уверен, что всегда будет доступен *Provider (который делается внутри angular после обработки службы или factory) (это может зависеть от того, что загрузилось первым) как angular лениво загружает модули.

Обратите внимание, что если вы хотите повторно ввести значения, которые должны рассматриваться как константы

Здесь более явный и, вероятно, более надежный способ сделать это + рабочий плункер

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

Ответ 6

Вы можете использовать $injection service для ввода услуги в конфигурацию

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

Ответ 7

Использование $injector для вызова методов службы в config

У меня была аналогичная проблема и разрешил ее с помощью службы $injector, как показано выше. Я попытался напрямую вставить услугу, но в итоге получил круговую зависимость от $http. Служба отображает модальную ошибку, и я использую ui-bootstrap modal, который также имеет зависимость от $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.")
            }
        }
    }

Ответ 8

Решение очень легко сделать

Примечание: это только для асинхронного вызова, поскольку служба не инициализируется при выполнении конфигурации.

Вы можете использовать метод run(). Пример:

  • Ваш сервис называется "MyService"
  • Вы хотите использовать его для выполнения asynchrone на провайдере "MyProvider"

Ваш код:

(function () { //To isolate code TO NEVER HAVE A GLOBAL VARIABLE!

    //Store your service into an internal variable
    //It 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;
    }]);
});

Ответ 9

Самый простой способ: $injector = angular.element(document.body).injector()

Затем используйте это для запуска invoke() или get()

Ответ 10

Ну, я немного потрудился с этим, но я действительно это сделал.

Я не знаю, устарели ли ответы из-за некоторых изменений в angular, но вы можете сделать это следующим образом:

Это ваш сервис:

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

И это config

.when('/beer-detail', {
  templateUrl : '/beer-detail',
  controller  : 'productDetailController',

  resolve: {
    beer: function(beerRetrievalService) {
      return beerRetrievalService.getRandomBeer();
    }
  }
})