2015-04-06 10 views
6

Ho una chiamata ajax all'interno di .run() che carica una variabile in $ rootScope Tale variabile è necessaria nel controller associato a una vista. A volte durante l'aggiornamento (F5) nel momento in cui viene caricato .controller non c'è nulla all'interno di $ rootScope.SuperCategories.Angular .controller() viene eseguito prima di .run() AngularJS

sampleApp.factory('SuperCategoryService', ['$http', '$q', '$rootScope', function ($http, $q, $rootScope){ 

    var SuperCategoryService = {}; 
    SuperCategoryService.SuperCategories = $rootScope.SuperCategories; 
    alert ($rootScope.SuperCategories); 
    return SuperCategoryService; 

}]); 



sampleApp.run(function($rootScope, $q, $http) { 

    var req = { 
     method: 'POST', 
     url: 'SuperCategoryData.txt', 
     //url: 'http://localhost/cgi-bin/superCategory.pl', 
     headers: { 'Content-Type': 'application/x-www-form-urlencoded' }//, 
     //data: { action: 'GET' } 
    }; 


    $rootScope.SuperCategories = []; 

    $rootScope.GetSuperCategories = function() { 

     var defer = $q.defer(); 
     $http(screq).then(function(response) { 
      $rootScope.SuperCategories = response.data; 
      //alert ($rootScope.SuperCategories); 
      defer.resolve($rootScope.SuperCategories); 
     }, function(error) { 
      defer.reject("Some error"); 
     }); 
     return defer.promise; 
    } 

    $rootScope.GetSuperCategories(); 


}); 

Come risolvere questo bug.

+1

Quando si dice che non c'è nulla nel servizio, si intende 'undefined' o' [] '? Se il più tardi, è perché la tua promessa non è ancora stata risolta. – floribon

+0

È vuoto [] .. Puoi aiutare come risolvere la promessa. –

risposta

3

NB: questa non è la risposta diretta alla domanda. Ho appena provato a riscrivere il tuo codice un po 'in modo da utilizzare le promesse e la fabbrica in modo più comune, potrebbe darti qualche idea su cosa può essere migliorato per rendere il codice asincrono più prevedibile.

controller chiama fabbrica per ottenere i dati, e quando promessa viene risolto voi si dispone di dati in $rootScope.SuperCategories

sampleApp.factory('SuperCategoryService', ['$http', '$q', function ($http, $q){ 

    var req = { 
     method: 'POST', 
     url: 'SuperCategoryData.txt', 
     //url: 'http://localhost/cgi-bin/superCategory.pl', 
     headers: { 'Content-Type': 'application/x-www-form-urlencoded' }//, 
     //data: { action: 'GET' } 
    }; 

    var SuperCategoryService = {}; 

    SuperCategoryService.SuperCategories = function() { 

     var defer = $q.defer(); 
     $http(screq).success(function(response) { 
      defer.resolve(response); 
     }); 
     return defer.promise; 
    } 


    return SuperCategoryService; 

}]); 



sampleApp.controller('myController', ['$scope', 'SuperCategoryService', function($scope, SuperCategoryService) { 

    SuperCategoryService.SuperCategories().then(function(data){ 
      $rootScope.SuperCategories = data; 
     }); 


}); 
+0

Questo è il modo corretto per farlo. Stai provando a temporizzare un evento di caricamento dei dati. Ci sono due modi per farlo, ma in entrambi i casi la risposta è una promessa (come Shershen ha sopra). Altrimenti, stai solo prediligendo l'ordine in cui avviene il bootstrap dell'applicazione (e anche in questo caso, non hai la garanzia che i dati siano lì). –

+0

Inoltre, $ rootScope in questo posto è probabilmente una cattiva idea. Vorrei raccomandare che il servizio tenga quei dati. –

+0

In questo caso ogni volta che il controller colpirà, chiamerà la funzione SuperCategoryService.SuperCategories(), che esegue internamente una richiesta Ajax. volevo evitare quella richiesta ajax. così in app.run(), stavo facendo la richiesta Ajax e provando a tenere i dati nella variabile $ rootScope. –

3

In questi casi si potrebbe qualcosa di simile.

sampleApp.run(function($rootScope, $q, $http) { 
    ... 
    // once the promise is resolved and SuperCategories are filled 
    $rootScope.$emit('init'); 
}); 


sampleApp.controller('AppCtrl', function ($rootScope) { 

    function init() { 
     ... 
    } 

    var unbindHandler = $rootScope.$on('init', function() { 
     init(); 
     unbindHandler(); 
    }); 

}); 

Si può fare cosa simile con $rootScope.$watch, ma dal momento che l'osservatore ha lancio iniziale, non è una buona misura per gli ascoltatori di una volta.

In ogni caso, il controller di livello superiore è un posto migliore per tutto il lavoro iniziale sull'oscilloscopio, non è necessario eseguire operazioni simili a questo in run().

Come risolvere questo bug.

Non è un bug ma il comportamento previsto del flusso di lavoro asincrono. Non dovresti mai fare affidamento sui ritardi quando risolvi le promesse, a meno che l'app non ti dia l'opportunità di controllarne le fasi (e Angular non ne dà una).

angolare applicazione funziona in tale ordine:

  • modulo di configurazione
  • modulo di corsa
  • funzione direttiva fabbrica
  • direttiva compilare
  • regolatore di direttiva (ng-controllore è anche una direttiva, a destra ?)
  • direttiva prelink
  • di rettiva (post) collegamento
  • percorso determinazione
  • controller di itinerario

Supponiamo che scimmia-patched $controllerProvider, così i controllori saranno umilmente attendere evento 'controllersReadySetGo' dal run() che può accadere un giorno. Ora indovina cosa succederà con, ad es. direttive pre/postlink che si basano seriamente sull'avere un'istanza del controllore.

0

2 anni più tardi :-D

Si potrebbe anche avvolgere la logica di controllo in un $ timeout pari a 0. Questo eseguirà la logica di controllo dopo il blocco corsa.

Problemi correlati