Внедрить сервис в приложение.конфиг

Я хочу ввести службу в приложение.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

несмотря на то, что принятый ответ говорит, Вы на самом деле CAN сделайте то, что вы намеревались сделать, но вам нужно настроить его как настраиваемый поставщик, чтобы он был доступен как услуга на этапе конфигурации.. Во-первых, измените свой Service поставщику, как показано ниже. Ключевое отличие здесь в том, что после установки значения defer, установить defer.promise свойство объекта 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, инкапсулирование службы в конкретный модуль в контексте вашего приложения. Выберите метод, который подходит именно вам. Также см. ниже заметки о 3-й альтернативе и полезные ссылки, чтобы помочь вам получить повесить все эти вещи

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 метод, который делает это лучше как поставщик уровня приложения, но вы также можете инкапсулировать это в самом объекте config, введя $provide в конфигурацию так:


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

посмотреть этот вопрос и ответ: инъекция зависимости AngularJS значения внутри модуля.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();
                    }
                });
            };
        }
    ]);

* * явно запрашивать службы из других модулей с помощью angular.инжектор **

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

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

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

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

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 service для внедрения службы в вас config

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 для вызова методов обслуживания в 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.")
            }
        }
    }

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

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

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

  1. ваш сервис называется "MyService"
  2. вы хотите использовать его для выполнения asynchrone на провайдере "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;
    }]);
});

самый простой способ: $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;
    }
  };
 });

и это config

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

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