используйте $ http внутри настраиваемого поставщика в конфигурации приложения, angular.js

90

Главный вопрос - возможно ли это? Я безуспешно пытался ..

основной app.js

...
var app = angular.module('myApp', ['services']);
app.config(['customProvider', function (customProvider) {

}]);
...

сам провайдер

var services = angular.module('services', []);
services.provider('custom', function ($http) {
});

И у меня такая ошибка:

Uncaught Error: Unknown provider: $http from services 

Любые идеи?

Благодарность!

Косметика
источник
posible
SET
чувак, да это правда, но я говорю о app.configчасти
Косметика
Я тоже знаю об этом ограничении, но подумал, что внутри провайдера это как-то возможно ..
Косметика

Ответы:

158

Итог:

  • Вы НЕ МОЖЕТЕ ввести услугу в раздел конфигурации провайдера .
  • Вы МОЖЕТЕ ввести услугу в раздел, который инициализирует услугу провайдера .

Детали:

Angular framework имеет двухэтапный процесс инициализации:

ФАЗА 1: Конфигурация

На этом configэтапе инициализируются все поставщики и выполняются все configразделы. В configсекции может содержать код , который конфигурирует объекты провайдера и , следовательно , они могут быть введены с объектами провайдера. Однако, поскольку провайдеры являются фабриками для сервисных объектов, и на этом этапе провайдеры не полностью инициализированы / настроены -> вы не можете попросить провайдера создать сервис для вас на этом этапе -> на стадии конфигурации вы не можете использовать / инъекционные услуги . Когда этот этап завершен, все поставщики готовы (после завершения этапа конфигурации больше нельзя будет выполнить настройку поставщика).

ФАЗА 2: Бег

Во время runфазы runвыполняются все разделы. На этом этапе поставщики готовы и могут создавать службы -> на runэтапе вы можете использовать / вводить службы .

Примеры:

1. Внедрение $httpсервиса в функцию инициализации провайдера НЕ БУДЕТ работать

//ERRONEOUS
angular.module('myModule').provider('myProvider', function($http) {
    // SECTION 1: code to initialize/configure the PROVIDER goes here (executed during `config` phase)
    ...

    this.$get = function() {
        // code to initialize/configure the SERVICE goes here (executed during `run` stage)

        return myService;
    };
});

Поскольку мы пытаемся внедрить $httpслужбу в функцию, которая выполняется на configэтапе, мы получим ошибку:

Uncaught Error: Unknown provider: $http from services 

На самом деле эта ошибка означает, что объект, $httpProviderкоторый используется для создания $httpслужбы, еще не готов (поскольку мы все еще находимся в configфазе).

2. Введение $httpсервиса в функцию инициализации сервиса БУДЕТ работать:

//OK
angular.module('myModule').provider('myProvider', function() {
    // SECTION 1: code to initialize/configure the PROVIDER goes here (executed during `config` phase)
    ...

    this.$get = function($http) {
        // code to initialize/configure the SERVICE goes here (executed during `run` stage)

        return myService;
    };
});

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

Дана Шалев
источник
63
Хороший ответ, но хотя он объясняет, как невозможно внедрить сервисы во время настройки, он не объясняет, как сделать HTTP POST / GET во время настройки. Это важно для приложений, настроенных с использованием значений, предоставляемых API.
Шон О'Делл,
3
@bebraw & Kosmetika - Единственное, что, как мне кажется, вам нужно будет запросить на этапе настройки, - это какой-то объект настроек. Возможно, он содержит конечную точку API, информацию о пользователе, языковой стандарт и языковые настройки пользователя и т. Д. В таком случае я бы рекомендовал как-то включить эту информацию в исходный код javascript. Вы можете использовать рендеринг на стороне сервера в index.html, чтобы добавить несколько настроек, чтобы они были доступны до инициализации вашего приложения. Ко всему прочему, я бы попытался выяснить, как это сделать после инициализации
Шон Кларк Хесс
2
@Sean: Как сделать HTTP POST / GET - это другой вопрос, чем OP (Можно ли использовать $ http внутри фазы конфигурации?), И, вероятно, заслуживает отдельного поста в целом; из-за синхронного характера фазы конфигурации Angular хороший способ предоставить данные на стороне сервера в ваш код конфигурации - это отобразить их как объект javascript на вашей HTML-странице во время рендеринга на стороне сервера (например <script>var config = <% = mySettings.toJson() %>;</script>). Это можно сделать с помощью механизма шаблонов, такого как Smarty для PHP, Jinja2 для Python, Nunchucks для NodeJS и т. Д.
Тревор,
4
@threed: вставка данных конфигурации непосредственно в HTML или js на сервере работает только в том случае, если ваш клиентский код поступает с того же сервера. С CORS теперь возможно (и очень желательно), чтобы клиентский код обслуживался с другого сервера, а данные обслуживались с отдельных серверов. В этих случаях нам нужно получить данные конфигурации с помощью HTTP.
Бернард
4
Хотя это ответ, это не ответ на заданный вопрос.
Эрик
64

Это может дать вам небольшое преимущество:

var initInjector = angular.injector(['ng']);
var $http = initInjector.get('$http');

Но будьте осторожны, обратные вызовы успеха / ошибки могут держать вас в состоянии гонки между запуском приложения и ответом сервера.

Коди
источник
6
"Принятый ответ" не помог моему провайдеру ... Я потратил 2 дня разочарования, пытаясь заставить это работать без всякой надежды. Ваш подход сработал сразу.
Дэйв Альперович
Можете ли вы уточнить, является ли созданный здесь экземпляр «настоящим» синглтоном службы или просто экземпляром службы, которая отбрасывается, когда Angular выполняет свою настоящую магию инжектора.
Эрик
Эрик, я не могу подтвердить это сейчас. Однако то, что я обычно делаю (если применимо), angular.injector(['mymodule'])таково, но я не уверен, что вы можете использовать этот подход для $httpслужбы. Я хочу сказать, что у меня есть. Не уверен, помогает это или нет: - /
Коди
2
Это должен быть принятый ответ. Я долго боролся, пытаясь заставить это работать, и этот подход сразу решил мою проблему. Я думаю, это может быть очень распространенная проблема. Спасибо @Cody
iamdash
5
Я подтверждаю, что принятое решение не работает для использования $ http в провайдере. Но ответ @Cody действительно помогает
Дино,
1

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

Вместо того, чтобы решить проблему фундаментальным образом, я обошел стороной. Создайте директиву, охватывающую все тело. Ex.

<body ng-app="app">
  <div mc-body>
    Hello World
  </div>
</body>

Теперь mc-bodyнеобходимо инициализировать перед рендерингом (один раз), например.

link: function(scope, element, attrs) {
  Auth.login().then() ...
}

Auth является услугой или поставщиком, напр.

.provider('Auth', function() {
  ... keep your auth configurations
  return {
    $get: function($http) {
      return {
        login: function() {
          ... do something about the http
        }
      }
    }
  }
})

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

И эта директива, как мне кажется, может опережать маршрутизацию, потому что маршрутизация также вводится через директиву ex. <ui-route />. Но я могу ошибаться в этом. Требуется дополнительное расследование.

Windmaomao
источник
Не могли бы вы подробнее рассказать о своем решении?
Марк
-2

На ваш вопрос «Есть идеи?» Я бы ответил «да». Но подождите, это еще не все!

Я предлагаю просто использовать JQuery в конфиге. Например:

var app = angular.module('myApp', ['services']);
app.config(['$anyProvider', function ($anyProvider) {
    $.ajax({
        url: 'www.something.com/api/lolol',
        success: function (result) {
            $anyProvider.doSomething(result);
        }
    });
}]);
Суамере
источник
$ customProvider в обратном вызове успеха включает $, как если бы это внутренний поставщик.
Джефф Фишер
1
Вы правы, что у меня было сочетание $ и не- $. Я обновил все до $.
Suamere