AngularJS: inizializza il servizio con dati asincroni


475

Ho un servizio AngularJS che voglio inizializzare con alcuni dati asincroni. Qualcosa come questo:

myModule.service('MyService', function($http) {
    var myData = null;

    $http.get('data.json').success(function (data) {
        myData = data;
    });

    return {
        setData: function (data) {
            myData = data;
        },
        doStuff: function () {
            return myData.getSomeData();
        }
    };
});

Ovviamente questo non funzionerà perché se qualcosa tenta di chiamare doStuff()prima di myDatatornare, riceverò un'eccezione puntatore null. Per quanto ne so leggendo alcune delle altre domande poste qui e qui ho alcune opzioni, ma nessuna di queste sembra molto pulita (forse mi manca qualcosa):

Servizio di installazione con "Esegui"

Quando configuri la mia app, procedi come segue:

myApp.run(function ($http, MyService) {
    $http.get('data.json').success(function (data) {
        MyService.setData(data);
    });
});

Quindi il mio servizio sarebbe simile a questo:

myModule.service('MyService', function() {
    var myData = null;
    return {
        setData: function (data) {
            myData = data;
        },
        doStuff: function () {
            return myData.getSomeData();
        }
    };
});

Questo funziona un po 'del tempo ma se i dati asincroni impiegano più tempo di quanto ci vuole per inizializzare tutto ottengo un'eccezione puntatore null quando chiamo doStuff()

Usa oggetti promettenti

Questo probabilmente funzionerebbe. L'unico aspetto negativo è che ovunque io chiamo MyService, dovrò sapere che doStuff () restituisce una promessa e tutto il codice che dovremo per noi theninteragire con la promessa. Preferirei solo aspettare che myData torni prima di caricare la mia applicazione.

Bootstrap manuale

angular.element(document).ready(function() {
    $.getJSON("data.json", function (data) {
       // can't initialize the data here because the service doesn't exist yet
       angular.bootstrap(document);
       // too late to initialize here because something may have already
       // tried to call doStuff() and would have got a null pointer exception
    });
});

Var globale Javascript Potrei inviare il mio JSON direttamente a una variabile Javascript globale:

HTML:

<script type="text/javascript" src="data.js"></script>

data.js:

var dataForMyService = { 
// myData here
};

Quindi sarebbe disponibile durante l'inizializzazione MyService:

myModule.service('MyService', function() {
    var myData = dataForMyService;
    return {
        doStuff: function () {
            return myData.getSomeData();
        }
    };
});

Funzionerebbe anche questo, ma poi ho una variabile javascript globale che ha un cattivo odore.

Queste sono le mie uniche opzioni? Una di queste opzioni è migliore delle altre? So che questa è una domanda piuttosto lunga, ma volevo dimostrare che ho cercato di esplorare tutte le mie opzioni. Qualsiasi consiglio sarebbe molto apprezzato.


angolare: bootstrap cammina in modo asincrono attraverso il codice per estrarre i dati da un server $http, quindi salva i dati in un servizio, quindi avvia un'app.
Steven Wexler,

Risposte:


327

Hai dato un'occhiata $routeProvider.when('/path',{ resolve:{...}? Può rendere l'approccio promettente un po 'più pulito:

Mostra una promessa al tuo servizio:

app.service('MyService', function($http) {
    var myData = null;

    var promise = $http.get('data.json').success(function (data) {
      myData = data;
    });

    return {
      promise:promise,
      setData: function (data) {
          myData = data;
      },
      doStuff: function () {
          return myData;//.getSomeData();
      }
    };
});

Aggiungi resolvealla tua configurazione del percorso:

app.config(function($routeProvider){
  $routeProvider
    .when('/',{controller:'MainCtrl',
    template:'<div>From MyService:<pre>{{data | json}}</pre></div>',
    resolve:{
      'MyServiceData':function(MyService){
        // MyServiceData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service
        return MyService.promise;
      }
    }})
  }):

Il controller non verrà istanziato prima che tutte le dipendenze siano state risolte:

app.controller('MainCtrl', function($scope,MyService) {
  console.log('Promise is now resolved: '+MyService.doStuff().data)
  $scope.data = MyService.doStuff();
});

Ho fatto un esempio su plnkr: http://plnkr.co/edit/GKg21XH0RwCMEQGUdZKH?p=preview


1
Grazie mille per la tua risposta! Funzionerebbe per me se non avessi già un servizio nella mappa di risoluzione che utilizza MyService. Ho aggiornato il tuo plunker con la mia situazione: plnkr.co/edit/465Cupaf5mtxljCl5NuF?p=preview . Esiste un modo per consentire a MyOtherService di attendere l'inizializzazione di MyService?
testing123

2
Immagino che incatenerei le promesse in MyOtherService - ho aggiornato il plunker con il concatenamento e alcuni commenti - come appare? plnkr.co/edit/Z7dWVNA9P44Q72sLiPjW?p=preview
joakimbl

3
Ho provato questo e ho riscontrato ancora alcuni problemi perché ho direttive e altri controller (il controller che uso con $ routeProvider sta gestendo una roba di navigazione primaria, secondaria ... ovvero "MyOtherService") che deve attendere fino a "MyService 'è stato risolto. Continuerò a provare e ad aggiornarlo con qualsiasi successo. Vorrei solo che ci fosse un gancio angolare in cui avrei potuto attendere il ritorno dei dati prima di inizializzare i miei controller e le mie direttive. Grazie ancora per il vostro aiuto. Se avessi un controller principale che racchiudesse tutto ciò avrebbe funzionato.
testing123

43
Una domanda qui: come assegnerai la resolveproprietà a un controller che non è menzionato in $routeProvider. Ad esempio <div ng-controller="IndexCtrl"></div>,. Qui, il controller viene esplicitamente citato e non caricato tramite routing. In tal caso, come ritarderebbe l'istanza del controller?
callmekatootie,

19
Cosa succede se non si utilizza il routing? È quasi come dire che non puoi scrivere un'app angolare con dati asincroni a meno che tu non usi il routing. Il modo consigliato per ottenere i dati in un'app è caricarli in modo asincrono, ma non appena si dispone di più di un controller e si inseriscono servizi, BOOM è impossibile.
wired_in

88

Basato sulla soluzione di Martin Atkins, ecco una soluzione angolare pura completa e concisa:

(function() {
  var initInjector = angular.injector(['ng']);
  var $http = initInjector.get('$http');
  $http.get('/config.json').then(
    function (response) {
      angular.module('config', []).constant('CONFIG', response.data);

      angular.element(document).ready(function() {
          angular.bootstrap(document, ['myApp']);
        });
    }
  );
})();

Questa soluzione utilizza una funzione anonima autoeseguente per ottenere il servizio $ http, richiedere la configurazione e iniettarla in una costante chiamata CONFIG quando diventa disponibile.

Una volta completamente, attendiamo che il documento sia pronto e quindi avviamo l'app Angular.

Questo è un leggero miglioramento rispetto alla soluzione di Martin, che ha rinviato il recupero della configurazione fino a quando il documento è pronto. Per quanto ne so, non c'è motivo di ritardare la chiamata $ http per questo.

Test unitari

Nota: ho scoperto che questa soluzione non funziona bene durante i test unitari quando il codice è incluso nel app.jsfile. Il motivo è che il codice sopra riportato viene eseguito immediatamente quando viene caricato il file JS. Ciò significa che il framework di test (nel mio caso Jasmine) non ha la possibilità di fornire un'implementazione fittizia di $http.

La mia soluzione, di cui non sono completamente soddisfatto, è stata quella di spostare questo codice nel nostro index.htmlfile, quindi l'infrastruttura di test dell'unità Grunt / Karma / Jasmine non lo vede.


1
Regole come "non inquinare l'ambito globale" dovrebbero essere seguite solo nella misura in cui rendono il nostro codice migliore (meno complesso, più gestibile, più sicuro, ecc.). Non riesco a vedere come questa soluzione sia migliore del semplice caricamento dei dati in una singola variabile globale. Cosa mi sto perdendo?
david004,

4
Ti consente di utilizzare il sistema di iniezione di dipendenza di Angular per accedere alla costante 'CONFIG' nei moduli che ne hanno bisogno, ma non rischi di intasare altri moduli che non lo fanno. Ad esempio, se hai utilizzato una variabile 'config' globale, è possibile che anche un altro codice di terze parti stia cercando la stessa variabile.
JBCP

1
Sono un novizio angolare, ecco alcune note su come ho risolto la dipendenza del modulo di configurazione nella mia app: gist.github.com/dsulli99/0be3e80db9b21ce7b989 ref: tutorials.jenkov.com/angularjs/… Grazie per questa soluzione.
dps,

7
È menzionato in un commento in una delle altre soluzioni bootstrap manuali di seguito, ma come novizio angolare che non l'ha individuato posso solo sottolineare che è necessario eliminare la direttiva ng-app nel codice html affinché funzioni correttamente - sta sostituendo il bootstrap automatico (tramite ng-app) con questo metodo manuale. Se non togli la ng-app, l'applicazione potrebbe effettivamente funzionare ma vedrai vari errori di provider sconosciuti nella console.
IrishDubGuy

49

Ho usato un approccio simile a quello descritto da @XMLilley ma volevo avere la possibilità di usare i servizi AngularJS come $httpcaricare la configurazione e fare ulteriori inizializzazioni senza l'uso di API di basso livello o jQuery.

Anche l'utilizzo resolvesu route non era un'opzione perché avevo bisogno che i valori fossero disponibili come costanti all'avvio della mia app, anche a module.config()blocchi.

Ho creato una piccola app AngularJS che carica la configurazione, le imposta come costanti sull'app effettiva e la avvia.

// define the module of your app
angular.module('MyApp', []);

// define the module of the bootstrap app
var bootstrapModule = angular.module('bootstrapModule', []);

// the bootstrapper service loads the config and bootstraps the specified app
bootstrapModule.factory('bootstrapper', function ($http, $log, $q) {
  return {
    bootstrap: function (appName) {
      var deferred = $q.defer();

      $http.get('/some/url')
        .success(function (config) {
          // set all returned values as constants on the app...
          var myApp = angular.module(appName);
          angular.forEach(config, function(value, key){
            myApp.constant(key, value);
          });
          // ...and bootstrap the actual app.
          angular.bootstrap(document, [appName]);
          deferred.resolve();
        })
        .error(function () {
          $log.warn('Could not initialize application, configuration could not be loaded.');
          deferred.reject();
        });

      return deferred.promise;
    }
  };
});

// create a div which is used as the root of the bootstrap app
var appContainer = document.createElement('div');

// in run() function you can now use the bootstrapper service and shutdown the bootstrapping app after initialization of your actual app
bootstrapModule.run(function (bootstrapper) {

  bootstrapper.bootstrap('MyApp').then(function () {
    // removing the container will destroy the bootstrap app
    appContainer.remove();
  });

});

// make sure the DOM is fully loaded before bootstrapping.
angular.element(document).ready(function() {
  angular.bootstrap(appContainer, ['bootstrapModule']);
});

Guardalo in azione (usando $timeoutinvece di $http) qui: http://plnkr.co/edit/FYznxP3xe8dxzwxs37hi?p=preview

AGGIORNARE

Consiglierei di utilizzare l'approccio descritto di seguito da Martin Atkins e JBCP.

AGGIORNAMENTO 2

Poiché ne avevo bisogno in più progetti, ho appena rilasciato un modulo pergolato che si occupa di questo: https://github.com/philippd/angular-deferred-bootstrap

Esempio che carica i dati dal back-end e imposta una costante chiamata APP_CONFIG sul modulo AngularJS:

deferredBootstrapper.bootstrap({
  element: document.body,
  module: 'MyApp',
  resolve: {
    APP_CONFIG: function ($http) {
      return $http.get('/api/demo-config');
    }
  }
});

11
deferredBootstrapper è la strada da percorrere
fatlinesofcode

44

Il caso "bootstrap manuale" può accedere ai servizi angolari creando manualmente un iniettore prima del bootstrap. Questo iniettore iniziale rimarrà da solo (non essere collegato ad alcun elemento) e includerà solo un sottoinsieme dei moduli che vengono caricati. Se tutto ciò di cui hai bisogno sono i servizi angolari di base, è sufficiente caricare semplicemente ng, in questo modo:

angular.element(document).ready(
    function() {
        var initInjector = angular.injector(['ng']);
        var $http = initInjector.get('$http');
        $http.get('/config.json').then(
            function (response) {
               var config = response.data;
               // Add additional services/constants/variables to your app,
               // and then finally bootstrap it:
               angular.bootstrap(document, ['myApp']);
            }
        );
    }
);

Ad esempio, puoi utilizzare il module.constantmeccanismo per rendere i dati disponibili per la tua app:

myApp.constant('myAppConfig', data);

Questo myAppConfigpuò ora essere iniettato come qualsiasi altro servizio, in particolare è disponibile durante la fase di configurazione:

myApp.config(
    function (myAppConfig, someService) {
        someService.config(myAppConfig.someServiceConfig);
    }
);

oppure, per un'app più piccola, puoi semplicemente inserire la configurazione globale direttamente nel tuo servizio, a spese della diffusione della conoscenza del formato di configurazione in tutta l'applicazione.

Naturalmente, poiché le operazioni asincrone qui bloccano il bootstrap dell'applicazione, e quindi bloccano la compilazione / collegamento del modello, è saggio utilizzare la ng-cloakdirettiva per impedire che il modello non analizzato venga visualizzato durante il lavoro. Puoi anche fornire una sorta di indicazione di caricamento nel DOM, fornendo un po 'di HTML che viene mostrato solo fino a quando AngularJS non inizializza:

<div ng-if="initialLoad">
    <!-- initialLoad never gets set, so this div vanishes as soon as Angular is done compiling -->
    <p>Loading the app.....</p>
</div>
<div ng-cloak>
    <!-- ng-cloak attribute is removed once the app is done bootstrapping -->
    <p>Done loading the app!</p>
</div>

Ho creato un esempio completo e funzionante di questo approccio su Plunker, caricando la configurazione da un file JSON statico come esempio.


Non penso che sia necessario rinviare $ http.get () fino a quando il documento non sarà pronto.
JBCP,

@JBCP sì, hai ragione che funziona altrettanto bene se si scambiano gli eventi in modo che non aspettiamo che il documento sia pronto fino a quando non viene restituita la risposta HTTP, con il vantaggio di poter eventualmente avviare l'HTTP richiesta più veloce. Solo la chiamata bootstrap deve attendere fino a quando il DOM è pronto.
Martin Atkins,

2
Ho creato un modulo pergolato con il tuo approccio: github.com/philippd/angular-deferred-bootstrap
philippd

@MartinAtkins, ho appena scoperto che il tuo ottimo approccio non funziona con Angular v1.1 +. Sembra che le prime versioni di Angular non capiscano "allora" fino a quando l'applicazione non viene avviata. Per vederlo nel tuo Plunk, sostituisci l'URL angolare con code.angularjs.org/1.1.5/angular.min.js
vkelman,

16

Ho avuto lo stesso problema: amo l' resolveoggetto, ma funziona solo per il contenuto di ng-view. Che cosa succede se si hanno controller (per nav di livello superiore, diciamo) che esistono al di fuori di ng-view e che devono essere inizializzati con i dati prima ancora che il routing inizi a verificarsi? Come possiamo evitare di perdere tempo sul lato server solo per farlo funzionare?

Usa il bootstrap manuale e una costante angolare . Un XHR naiive ti fornisce i tuoi dati e il bootstrap angolare nel suo callback, che affronta i tuoi problemi asincroni. Nell'esempio seguente, non è nemmeno necessario creare una variabile globale. I dati restituiti esistono solo a scopo angolare come iniettabili e non sono nemmeno presenti all'interno di controller, servizi, ecc. A meno che non li iniettiate. (Proprio come inietteresti l'output del tuo resolveoggetto nel controller per una vista indirizzata.) Se preferisci in seguito interagire con quei dati come servizio, puoi creare un servizio, iniettare i dati e nessuno sarà mai più saggio .

Esempio:

//First, we have to create the angular module, because all the other JS files are going to load while we're getting data and bootstrapping, and they need to be able to attach to it.
var MyApp = angular.module('MyApp', ['dependency1', 'dependency2']);

// Use angular's version of document.ready() just to make extra-sure DOM is fully 
// loaded before you bootstrap. This is probably optional, given that the async 
// data call will probably take significantly longer than DOM load. YMMV.
// Has the added virtue of keeping your XHR junk out of global scope. 
angular.element(document).ready(function() {

    //first, we create the callback that will fire after the data is down
    function xhrCallback() {
        var myData = this.responseText; // the XHR output

        // here's where we attach a constant containing the API data to our app 
        // module. Don't forget to parse JSON, which `$http` normally does for you.
        MyApp.constant('NavData', JSON.parse(myData));

        // now, perform any other final configuration of your angular module.
        MyApp.config(['$routeProvider', function ($routeProvider) {
            $routeProvider
              .when('/someroute', {configs})
              .otherwise({redirectTo: '/someroute'});
          }]);

        // And last, bootstrap the app. Be sure to remove `ng-app` from your index.html.
        angular.bootstrap(document, ['NYSP']);
    };

    //here, the basic mechanics of the XHR, which you can customize.
    var oReq = new XMLHttpRequest();
    oReq.onload = xhrCallback;
    oReq.open("get", "/api/overview", true); // your specific API URL
    oReq.send();
})

Ora, la tua NavDatacostante esiste. Vai avanti e iniettalo in un controller o servizio:

angular.module('MyApp')
    .controller('NavCtrl', ['NavData', function (NavData) {
        $scope.localObject = NavData; //now it's addressable in your templates 
}]);

Ovviamente, l'uso di un oggetto XHR nudo elimina una serie di prelibatezze che $httpJQuery si sarebbe preso cura di te, ma questo esempio funziona senza dipendenze speciali, almeno per un semplice get. Se desideri un po 'più di energia per la tua richiesta, carica una libreria esterna per aiutarti. Ma non penso che sia possibile accedere agli $httpstrumenti angolari o ad altri strumenti in questo contesto.

(Posto relativo SO )


8

Quello che puoi fare è nel tuo .config per l'app è creare l'oggetto di risoluzione per il percorso e nella funzione passare $ q (oggetto promessa) e il nome del servizio da cui dipendi e risolvere la promessa nella funzione di callback per $ http nel servizio in questo modo:

CONFIGURAZIONE DEL PERCORSO

app.config(function($routeProvider){
    $routeProvider
     .when('/',{
          templateUrl: 'home.html',
          controller: 'homeCtrl',
          resolve:function($q,MyService) {
                //create the defer variable and pass it to our service
                var defer = $q.defer();
                MyService.fetchData(defer);
                //this will only return when the promise
                //has been resolved. MyService is going to
                //do that for us
                return defer.promise;
          }
      })
}

Angular non renderà il modello o renderà disponibile il controller finché non sarà stato chiamato defer.resolve (). Possiamo farlo nel nostro servizio:

SERVIZIO

app.service('MyService',function($http){
       var MyService = {};
       //our service accepts a promise object which 
       //it will resolve on behalf of the calling function
       MyService.fetchData = function(q) {
             $http({method:'GET',url:'data.php'}).success(function(data){
                 MyService.data = data;
                 //when the following is called it will
                 //release the calling function. in this
                 //case it's the resolve function in our
                 //route config
                 q.resolve();
             }
       }

       return MyService;
});

Ora che MyService ha i dati assegnati alla sua proprietà data e la promessa nell'oggetto di risoluzione del percorso è stata risolta, il nostro controller per il percorso prende vita e possiamo assegnare i dati dal servizio al nostro oggetto controller.

CONTROLLER

  app.controller('homeCtrl',function($scope,MyService){
       $scope.servicedata = MyService.data;
  });

Ora tutti i nostri vincoli nell'ambito del controller saranno in grado di utilizzare i dati originati da MyService.


Ci proverò quando avrò più tempo. Sembra simile a quello che gli altri stavano cercando di fare in ngModules.
testing123,

1
Mi piace questo approccio e l'ho usato prima, ma attualmente sto cercando di capire come farlo in modo chiaro quando ho diversi percorsi, ognuno dei quali può dipendere o meno dai dati precaricati. Qualche idea su questo?
Ivarni

tra l'altro, mi sto impegnando affinché ogni servizio che richiede dati precaricati faccia la richiesta quando viene inizializzato e restituisce una promessa e quindi imposta risolve oggetti con i servizi richiesti dalle diverse rotte. Vorrei solo che ci fosse un modo meno prolisso.
Ivarni

1
@dewd Questo è quello a cui stavo puntando, ma preferirei di gran lunga se ci fosse un modo per dire "recupera prima tutto questo materiale indipendentemente da quale percorso viene caricato" senza dover ripetere i miei blocchi di risoluzione. Tutti hanno qualcosa da cui dipendono. Ma non è un grosso problema, sembrerebbe solo un po 'più ASCIUTTO :)
Ivarni

2
questo è il percorso che ho finito prendendo tranne che dovevo creare resolveun oggetto con una proprietà come funzione. così finì per essereresolve:{ dataFetch: function(){ // call function here } }
aron.duby

5

Quindi ho trovato una soluzione. Ho creato un servizio angularJS, lo chiameremo MyDataRepository e ho creato un modulo per esso. Fornisco quindi questo file javascript dal mio controller lato server:

HTML:

<script src="path/myData.js"></script>

Lato server:

@RequestMapping(value="path/myData.js", method=RequestMethod.GET)
public ResponseEntity<String> getMyDataRepositoryJS()
{
    // Populate data that I need into a Map
    Map<String, String> myData = new HashMap<String,String>();
    ...
    // Use Jackson to convert it to JSON
    ObjectMapper mapper = new ObjectMapper();
    String myDataStr = mapper.writeValueAsString(myData);

    // Then create a String that is my javascript file
    String myJS = "'use strict';" +
    "(function() {" +
    "var myDataModule = angular.module('myApp.myData', []);" +
    "myDataModule.service('MyDataRepository', function() {" +
        "var myData = "+myDataStr+";" +
        "return {" +
            "getData: function () {" +
                "return myData;" +
            "}" +
        "}" +
    "});" +
    "})();"

    // Now send it to the client:
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.add("Content-Type", "text/javascript");
    return new ResponseEntity<String>(myJS , responseHeaders, HttpStatus.OK);
}

Posso quindi iniettare MyDataRepository dove mai ne ho bisogno:

someOtherModule.service('MyOtherService', function(MyDataRepository) {
    var myData = MyDataRepository.getData();
    // Do what you have to do...
}

Questo ha funzionato alla grande per me, ma sono aperto a qualsiasi feedback se qualcuno ne ha. }


Mi piace il tuo approccio modulare. Ho scoperto che $ routeScope è disponibile per il servizio che richiede dati e puoi assegnargli dati nel callback $ http.success. Tuttavia, l'utilizzo di $ routeScope per gli articoli non globali crea un odore e i dati dovrebbero davvero essere assegnati all'ambito $ controller. Sfortunatamente, penso che il tuo approccio, sebbene innovativo, non sia l'ideale (rispetto però per trovare qualcosa che funzioni per te). Sono solo sicuro che ci deve essere una sola risposta sul lato client che in qualche modo attende i dati e consenta l'assegnazione all'ambito. La ricerca continua!
rugiada del

Nel caso sia utile a qualcuno, recentemente ho visto alcuni approcci diversi guardando i moduli che altre persone hanno scritto e aggiunto al sito Web ngModules. Quando avrò più tempo dovrò iniziare a usarne uno o capire cosa hanno fatto e aggiungerlo alle mie cose.
testing123

2

Inoltre, è possibile utilizzare le seguenti tecniche per fornire il proprio servizio a livello globale, prima che vengano eseguiti i controller effettivi: https://stackoverflow.com/a/27050497/1056679 . Risolvi semplicemente i tuoi dati a livello globale e poi passali al tuo servizio in runblocco, ad esempio.


1

Puoi usare JSONP per caricare in modo asincrono i dati di servizio. La richiesta JSONP verrà effettuata durante il caricamento della pagina iniziale e i risultati saranno disponibili prima dell'avvio dell'applicazione. In questo modo non sarà necessario gonfiare il routing con risoluzioni ridondanti.

Il tuo HTML sarebbe simile a questo:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>

function MyService {
  this.getData = function(){
    return   MyService.data;
  }
}
MyService.setData = function(data) {
  MyService.data = data;
}

angular.module('main')
.service('MyService', MyService)

</script>
<script src="/some_data.php?jsonp=MyService.setData"></script>

-1

Il modo più semplice per recuperare qualsiasi inizializzazione usa la directory ng-init.

Inserisci l'ambito div di ng-init dove desideri recuperare i dati di init

index.html

<div class="frame" ng-init="init()">
    <div class="bit-1">
      <div class="field p-r">
        <label ng-show="regi_step2.address" class="show-hide c-t-1 ng-hide" style="">Country</label>
        <select class="form-control w-100" ng-model="country" name="country" id="country" ng-options="item.name for item in countries" ng-change="stateChanged()" >
        </select>
        <textarea class="form-control w-100" ng-model="regi_step2.address" placeholder="Address" name="address" id="address" ng-required="true" style=""></textarea>
      </div>
    </div>
  </div>

index.js

$scope.init=function(){
    $http({method:'GET',url:'/countries/countries.json'}).success(function(data){
      alert();
           $scope.countries = data;
    });
  };

NOTA: è possibile utilizzare questa metodologia se non si dispone dello stesso codice più di un posto.


Non è consigliabile utilizzare ngInit secondo i documenti: docs.angularjs.org/api/ng/directive/ngInit
fodma1
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.