Внедрить сервис в 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 из EditorApp

Как исправить настройки и внедрить этот сервис?

10 ответов

Решение

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

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

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

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

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

Настройте свой сервис как пользовательский поставщик AngularJS

Несмотря на то, что говорится в ответе "Принято", вы на самом деле МОЖЕТЕ делать то, что намеревались сделать, но вам нужно настроить его в качестве настраиваемого поставщика, чтобы он был доступен в качестве службы на этапе настройки. Во-первых, измените свой 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-минутное объяснение и демонстрация этого на egghead.io, и это один из бесплатных уроков! Я в основном изменил его демонстрацию, сделав это $http конкретный в контексте этого запроса
  • Посмотреть руководство разработчика AngularJS по провайдерам
  • Существует также отличное объяснение о factory/service/provider на clevertech.biz.

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

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

См. Этот вопрос и ответ: AngularJS-инъекция зависимости значения внутри module.config

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

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

** Явно запрашивать услуги у других модулей, используя angular.injector **

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

Тем не менее, я не уверен, если *Provider (который выполняется внутренне с помощью 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();
});

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

app.config (функция ($ предоставить){

    $ provide.decorator ("$ exceptionHandler", функция ($ делегат, $ инжектор){
        функция возврата (исключение, причина){
            var $rootScope = $injector.get("$rootScope");
            $rootScope.addError({сообщение:"Исключение", причина: исключение});
            $ делегат (исключение, причина);
        };
    });

});

Источник: http://odetocode.com/blogs/scott/archive/2014/04/21/better-error-handling-in-angularjs.aspx

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

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

У меня была похожая проблема, и я решил ее с помощью службы $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. Ваш сервис называется "MyService"
  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;
    }]);
});

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

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

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

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

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

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

Другие вопросы по тегам