usa $ http all'interno del provider personalizzato nella configurazione dell'app, angular.js


90

La domanda principale: è possibile? Ho provato senza fortuna ..

app.js principale

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

}]);
...

provider stesso

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

E ho un tale errore:

Uncaught Error: Unknown provider: $http from services 

Qualche idea?

Grazie!



amico, sì, è vero, ma sto parlando della app.configparte
Kosmetika


So anche di questa limitazione, ma ho pensato che all'interno del provider fosse possibile in qualche modo ..
Kosmetika

Risposte:


158

La linea di fondo è:

  • È NON POTETE iniettare un servizio nella sezione di configurazione del provider .
  • È POSSIBILE inserire un servizio nella sezione che inizializza il servizio del provider .

Dettagli:

Il framework angolare ha un processo di inizializzazione in 2 fasi:

FASE 1: Config

Durante la configfase vengono inizializzati tutti i provider e configvengono eseguite tutte le sezioni. Le configsezioni possono contenere codice che configura gli oggetti provider e quindi possono essere iniettati con oggetti provider. Tuttavia, poiché i provider sono le fabbriche per gli oggetti del servizio e in questa fase i provider non sono completamente inizializzati / configurati -> non puoi chiedere al provider di creare un servizio per te in questa fase -> nella fase di configurazione non puoi usare / iniettare servizi . Quando questa fase è completata, tutti i provider sono pronti (non è più possibile eseguire la configurazione del provider dopo il completamento della fase di configurazione).

FASE 2: corri

Durante la runfase runvengono eseguite tutte le sezioni. In questa fase i provider sono pronti e possono creare servizi -> durante la runfase è possibile utilizzare / iniettare servizi .

Esempi:

1. L'iniezione del $httpservizio nella funzione di inizializzazione del provider NON funzionerà

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

Dato che stiamo cercando di iniettare il $httpservizio in una funzione che viene eseguita durante la configfase, otterremo un errore:

Uncaught Error: Unknown provider: $http from services 

Ciò che questo errore sta effettivamente dicendo è che il file $httpProviderutilizzato per creare il $httpservizio non è ancora pronto (poiché siamo ancora in configfase).

2. Iniettare il $httpservizio per l'inizializzazione servizio funzione WILL lavoro:

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

Poiché ora stiamo iniettando il servizio nella funzione di inizializzazione del servizio, che viene eseguita durante la runfase, questo codice funzionerà.


63
Buona risposta, ma mentre spiega come non sia possibile iniettare servizi durante la configurazione, non spiega come effettuare un HTTP POST / GET durante la configurazione. Questo è importante per le applicazioni configurate utilizzando i valori forniti da un'API.
Sean O'Dell

3
@bebraw & Kosmetika - L'unica cosa che posso pensare che dovresti richiedere durante la fase di configurazione è una sorta di oggetto impostazioni. Forse contiene l'endpoint dell'API, le informazioni sull'utente, le impostazioni locali e della lingua dell'utente, ecc. In tal caso, consiglierei di includere tali informazioni nel sorgente javascript in qualche modo. Puoi utilizzare il rendering lato server su index.html per inserire alcune impostazioni in modo che siano disponibili prima dell'inizializzazione dell'app. Tutto il resto, proverei a capire come farlo post-init
Sean Clark Hess,

2
@Sean: Come creare un HTTP POST / GET è una domanda diversa da quella dell'OP (è possibile usare $ http all'interno della fase di configurazione?), E probabilmente merita un post a parte; a causa della natura sincrona della fase di configurazione di Angular, un buon modo per fornire dati lato server al codice di configurazione è renderlo come un oggetto javascript nella pagina HTML durante il rendering lato server (ad esempio <script>var config = <% = mySettings.toJson() %>;</script>). Questo può essere fatto utilizzando un motore di template come Smarty per PHP, Jinja2 per Python, Nunchucks per NodeJS, ecc.
Trevor

4
@threed: l'inserimento dei dati di configurazione direttamente nell'HTML o nel js sul server funziona solo se il codice client proviene dallo stesso server. Con CORS, è ora possibile (e molto desiderabile) che il codice client venga servito da un server diverso e che i dati vengano serviti da server separati. In questi casi, è necessario recuperare i dati di configurazione utilizzando HTTP.
Bernard

4
Sebbene questa sia una risposta, non è la risposta alla domanda che è stata posta.
Eric,

64

Questo potrebbe darti una piccola leva:

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

Ma fai attenzione, i callback di successo / errore potrebbero mantenerti in una condizione di competizione tra l'avvio dell'app e la risposta del server.


6
La "risposta accettata" non è riuscita per il mio provider ... Ho passato 2 giorni di frustrazione cercando di farlo funzionare senza speranza. Il tuo approccio ha funzionato immediatamente.
Dave Alperovich

Puoi chiarire se l'istanza creata qui è il "vero" servizio singleton o solo un'istanza del servizio che viene scartata quando Angular fa la sua vera magia iniettore.
Eric

Eric, non posso confermarlo in questo momento. Tuttavia, quello che faccio di solito (se applicabile) è angular.injector(['mymodule']), ma non sono sicuro che tu possa utilizzare questo approccio per il $httpservizio. Voglio dire che l'ho fatto però. Non sono sicuro se questo aiuti o meno: - /
Cody

2
Questa dovrebbe essere la risposta accettata. Ho lottato per un bel po 'cercando di farlo funzionare e questo approccio ha risolto immediatamente il mio problema. Penso che questo possa essere un problema molto comune. Grazie @Cody
iamdash

5
Confermo che la soluzione accettata non funziona per l'utilizzo di $ http nel provider. Ma la risposta di @Cody fa il trucco
Dino

1

Questa è una vecchia domanda, sembra che abbiamo qualcosa da fare se vogliamo fare affidamento sulle funzionalità principali della libreria.

Invece di risolvere il problema in modo fondamentale, quello che ho fatto è bypassare. Crea una direttiva che avvolga l'intero corpo. Ex.

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

Ora mc-bodydeve essere inizializzato prima del rendering (una volta), es.

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

Auth è un servizio o un fornitore, es.

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

Mi sembra di avere il controllo sull'ordine del bootstrap, è dopo che il bootstrap regolare risolve tutta la configurazione del provider e quindi prova a inizializzare la mc-bodydirettiva.

E questa direttiva mi sembra possa essere prima del routing, perché anche il routing viene iniettato tramite una direttiva ex. <ui-route />. Ma posso sbagliarmi su questo. Ha bisogno di ulteriori indagini.


Puoi per favore elaborare la tua soluzione?
Mark

-2

In risposta alla tua domanda "Qualche idea?", Avrei risposto con "sì". Ma aspetta, c'è di più!

Suggerisco di usare solo JQuery nel file config. Per esempio:

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 nel callback di successo include $ come se fosse un provider interno.
Jeff Fischer

1
Hai ragione che avevo un mix di $ e non- $. L'ho aggiornato in modo che sia $.
Suamere
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.