використовувати $ 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 

Будь-які ідеї?

Дякую!



чоловіче, так, це правда, але я кажу про app.configчастину
Kosmetika


я також знаю про це обмеження, але думав, що всередині провайдера це якось можливо ..
Kosmetika

Відповіді:


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

Це старе питання, здається, у нас щось відбувається з курячими яйцями, якщо ми хочемо покластись на основні можливості бібліотеки.

Замість того, щоб вирішити проблему принципово, я зробив це обхід. Створіть директиву, яка охоплює все тіло. Напр.

<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 />. Але я можу помилитися в цьому. Потрібне ще якесь розслідування.


Ви можете, будь ласка, детальніше розглянути своє рішення?
Марк

-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
Ви маєте рацію, що у мене було поєднання $, а не- $. Я оновив його до $.
Суамер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.