Verwenden Sie $ http im benutzerdefinierten Anbieter in der App-Konfiguration angular.js

90

Die Hauptfrage - ist es möglich? Ich habe es ohne Glück versucht ..

Haupt-App.js

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

}]);
...

Anbieter selbst

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

Und ich habe einen solchen Fehler:

Uncaught Error: Unknown provider: $http from services 

Irgendwelche Ideen?

Vielen Dank!

Kosmetika
quelle
Mann, ja, es ist wahr, aber ich spreche über app.configTeil
Kosmetika
Ich weiß auch über diese Einschränkung Bescheid, dachte aber, dass es innerhalb des Anbieters irgendwie möglich ist.
Kosmetika

Antworten:

158

Das Endergebnis ist:

  • Sie NICHT einen Dienst in den Provider - Konfiguration Abschnitt injizieren .
  • Sie CAN einen Dienst in den Abschnitt injizieren , die der Anbieter-Dienst initialisiert .

Einzelheiten:

Angular Framework hat einen 2-Phasen-Initialisierungsprozess:

PHASE 1: Konfig

Während der configPhase werden alle Anbieter initialisiert und alle configAbschnitte ausgeführt. Die configAbschnitte können Code enthalten, der die Anbieterobjekte konfiguriert, und daher können ihnen Anbieterobjekte injiziert werden. Da die Anbieter jedoch die Fabriken für die Serviceobjekte sind und die Anbieter zu diesem Zeitpunkt noch nicht vollständig initialisiert / konfiguriert sind -> können Sie den Anbieter in dieser Phase nicht bitten, einen Dienst für Sie zu erstellen -> in der Konfigurationsphase können Sie / nicht verwenden Injektionsdienste . Nach Abschluss dieser Phase sind alle Anbieter bereit (nach Abschluss der Konfigurationsphase kann keine Anbieterkonfiguration mehr durchgeführt werden).

PHASE 2: Ausführen

Während der runPhase werden alle runAbschnitte ausgeführt. Zu diesem Zeitpunkt sind die Anbieter bereit und können Dienste erstellen -> während der runPhase können Sie Dienste verwenden / injizieren .

Beispiele:

1. Injektion der $httpService Provider Initialisierungsfunktion WILL NOT Arbeit

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

Da wir versuchen, den $httpDienst in eine Funktion einzufügen, die während der configPhase ausgeführt wird, wird eine Fehlermeldung angezeigt:

Uncaught Error: Unknown provider: $http from services 

Was dieser Fehler tatsächlich aussagt, ist, dass das, $httpProviderwas zum Erstellen des $httpDienstes verwendet wird, noch nicht bereit ist (da wir uns noch in der configPhase befinden).

2. Injizieren $httpDienst in den Dienst Initialisierungsfunktion WILL Arbeit:

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

Da wir den Service jetzt in die Service-Initialisierungsfunktion runeinfügen , die während der Phase ausgeführt wird, funktioniert dieser Code.

Dana Shalev
quelle
63
Gute Antwort, aber es erklärt zwar, dass es nicht möglich ist, Dienste während der Konfiguration einzuschleusen, aber nicht, wie während der Konfiguration ein HTTP-POST / GET erstellt wird. Dies ist wichtig für Anwendungen, die mit Werten konfiguriert werden, die von einer API bereitgestellt werden.
Sean O'Dell
3
@bebraw & Kosmetika - Ich kann mir nur vorstellen, dass Sie während der Konfigurationsphase eine Art Einstellungsobjekt anfordern müssen. Möglicherweise enthält es den API-Endpunkt, Benutzerinformationen, das Gebietsschema und die Spracheinstellungen des Benutzers usw. Wenn dies der Fall ist, würde ich empfehlen, diese Informationen irgendwie in die Javascript-Quelle aufzunehmen. Sie können serverseitiges Rendering in index.html verwenden, um einige Einstellungen vorzunehmen, damit diese verfügbar sind, bevor Ihre App initialisiert wird. Alles andere würde ich versuchen herauszufinden, wie es nach der Initiale geht
Sean Clark Hess
2
@ Sean: Wie man einen HTTP-POST / GET erstellt, ist eine andere Frage als die des OP (Ist es möglich, $ http in der Konfigurationsphase zu verwenden?) Und verdient wahrscheinlich einen separaten Beitrag insgesamt. Aufgrund der Synchronität der Konfigurationsphase von Angular besteht eine gute Möglichkeit, serverseitige Daten für Ihren Konfigurationscode bereitzustellen, darin, sie während des serverseitigen Renderns als Javascript-Objekt auf Ihrer HTML-Seite zu rendern (z <script>var config = <% = mySettings.toJson() %>;</script>. B. ). Dies kann mit einer Template-Engine wie Smarty für PHP, Jinja2 für Python, Nunchucks für NodeJS usw. erfolgen
Trevor
4
@threed: Das direkte Einfügen von Konfigurationsdaten in HTML oder js auf dem Server funktioniert nur, wenn Ihr Clientcode vom selben Server stammt. Mit CORS ist es jetzt möglich (und sehr wünschenswert), dass der Clientcode von einem anderen Server und die Daten von separaten Servern bereitgestellt werden. In diesen Fällen müssen wir Konfigurationsdaten über HTTP abrufen.
Bernard
4
Dies ist zwar eine Antwort, aber nicht die Antwort auf die gestellte Frage.
Eric
64

Dies könnte Ihnen einen kleinen Hebel geben:

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

Aber seien Sie vorsichtig, die Erfolgs- / Fehlerrückrufe können Sie in einem Wettlauf zwischen dem Start der App und der Serverantwort halten.

Cody
quelle
6
Die "akzeptierte Antwort" ist für meinen Provider fehlgeschlagen ... Ich habe 2 Tage lang frustriert versucht, diese Funktion ohne Hoffnung zum Laufen zu bringen. Ihr Ansatz hat sofort funktioniert.
Dave Alperovich
Können Sie klären, ob es sich bei der hier erstellten Instanz um den "echten" Dienst-Singleton handelt oder nur um eine Instanz des Dienstes, die verworfen wird, wenn Angular seine eigentliche Injektor-Magie ausführt?
Eric
Eric, das kann ich derzeit nicht bestätigen. Normalerweise mache ich jedoch (falls zutreffend) angular.injector(['mymodule'])- aber ich bin mir nicht sicher, ob Sie diesen Ansatz für den $httpService verwenden können. Ich möchte sagen, dass ich es getan habe. Nicht sicher, ob dies hilft oder nicht: - /
Cody
2
Dies sollte die akzeptierte Antwort sein. Ich kämpfte eine Weile, während ich versuchte, dies zum Laufen zu bringen, und dieser Ansatz löste mein Problem sofort. Ich denke, dass dies ein sehr häufiges Problem sein kann. Danke @Cody
iamdash
5
Ich bestätige, dass die akzeptierte Lösung für die Verwendung von $ http im Anbieter nicht funktioniert. Aber @Cody 's Antwort macht den Trick
Dino
1

Dies ist eine alte Frage, anscheinend haben wir etwas mit Hühnerei zu tun, wenn wir uns auf die Kernkompetenz der Bibliothek verlassen wollen.

Anstatt das Problem grundlegend zu lösen, habe ich es umgangen. Erstellen Sie eine Direktive, die den gesamten Körper umschließt. Ex.

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

Muss jetzt mc-bodyvor dem Rendern (einmal) initialisiert werden, z.

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

Auth ist ein Dienstleister oder Anbieter, z.

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

Mir scheint, ich habe die Kontrolle über die Reihenfolge des Bootstraps. Nachdem der reguläre Bootstrap die gesamte Anbieterkonfiguration aufgelöst hat und dann versucht, die mc-bodyDirektive zu initialisieren .

Und diese Direktive scheint mir dem Routing voraus zu sein, da das Routing auch über eine Direktive ex injiziert wird. <ui-route />. Aber ich kann mich irren. Benötigt weitere Untersuchungen.

Windmaomao
quelle
Können Sie bitte Ihre Lösung näher erläutern?
Mark
-2

Als Antwort auf Ihre Frage "Irgendwelche Ideen?" Hätte ich mit "Ja" geantwortet. Aber warte, da ist noch mehr!

Ich schlage vor, nur JQuery in der Konfiguration zu verwenden. Beispielsweise:

var app = angular.module('myApp', ['services']);
app.config(['$anyProvider', function ($anyProvider) {
    $.ajax({
        url: 'www.something.com/api/lolol',
        success: function (result) {
            $anyProvider.doSomething(result);
        }
    });
}]);
Suamere
quelle
$ customProvider im Erfolgsrückruf enthält $, als wäre es ein interner Anbieter.
Jeff Fischer
1
Du hast Recht, dass ich eine Mischung aus $ und nicht- $ hatte. Ich habe es auf $ aktualisiert.
Suamere