2015-04-06 19 views
6

Mam wywołanie ajax wewnątrz pliku .run(), który ładuje zmienną do $ rootScope Ta zmienna jest wymagana w kontrolerze związanym z widokiem. Czasami podczas odświeżania (F5) przed załadowaniem .controller nie ma nic w $ rootScope.SuperCategories.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(); 


}); 

Jak naprawić ten błąd.

+1

Kiedy mówisz, że w usłudze nie ma nic, masz na myśli 'niezdefiniowany' lub' [] '? Jeśli później, to dlatego, że twoja obietnica nie została jeszcze rozwiązana. – floribon

+0

Jego puste [] .. Czy możesz pomóc, jak rozwiązać obietnicę. –

Odpowiedz

3

UWAGA: nie jest to bezpośrednia odpowiedź na Twoje pytanie. Właśnie próbowałem przepisać twój kod trochę w taki sposób, aby wykorzystać obietnice i fabrykę w bardziej powszechny sposób, może to da ci kilka pomysłów, co można poprawić, aby kod asynchroniczny działał bardziej przewidywalnie.

Controller wzywa fabrykę aby uzyskać dane, a gdy Obietnica został rozwiązany masz ci dane $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

To jest właściwy sposób, aby to zrobić. Próbujesz ustawić czas zdarzenia ładowania danych. Można to zrobić na dwa sposoby, ale w obu przypadkach odpowiedź jest obietnicą (podobnie jak w przypadku shershen). W przeciwnym razie po prostu żerujesz, w jakiej kolejności odbywa się bootstrap aplikacji (a nawet wtedy nie masz gwarancji, że dane tam są). –

+0

Również $ rootScope w tym miejscu jest prawdopodobnie złym pomysłem. Poleciłbym serwisowi utrzymać te dane. –

+0

W tym przypadku, gdy kontroler uderzy, wywoła funkcję SuperCategoryService.SuperCategories(), która wewnętrznie zgłasza żądanie ajax. chciałem uniknąć tej prośby o ajax. więc w app.run() robiłem zapytanie ajaxowe i próbowałem przechowywać dane w zmiennej $ rootScope. –

3

W takich przypadkach można było coś takiego.

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

}); 

Można zrobić coś podobnego z $rootScope.$watch, ale od Watcher ma pierwszego uruchomienia, nie jest dobrym rozwiązaniem dla słuchaczy jednorazowych.

W każdym razie, kontroler najwyższego poziomu jest lepszym miejscem dla wszystkich początkowych prac nad zakresem, nie ma potrzeby robienia czegoś takiego w run().

Jak naprawić ten błąd.

Nie jest to błąd, ale oczekiwane zachowanie asynchronicznego przepływu pracy. Nigdy nie należy polegać na opóźnieniach przy rozpatrywaniu obietnic, chyba że aplikacja daje możliwość kontrolowania swoich faz (a Angular jej nie daje).

kątowa aplikacja działa w takiej kolejności:

  • moduł konfiguracyjny
  • moduł prowadzony
  • funkcja dyrektywa fabryka
  • dyrektywa kompilacji
  • dyrektywa kontroler (ng-kontroler jest również dyrektywa, prawo ?)
  • dyrektywa prelink
  • di Odczynniki (post) Link
  • trasa resolve
  • kontroler trasy

Załóżmy, że małpa-połatany $controllerProvider, więc kontrolerzy będą pokornie czekać na imprezy '' controllersReadySetGo od run(), które mogą się zdarzyć w przyszłości. Teraz zgadnij, co stanie się z np. dyrektywy pre/postlinks, które poważnie polegają na posiadaniu instancji kontrolera.

0

2 lata później :-D

Można też owinąć Logic Controller do $ timeout 0. wykona logiki kontrolera po bloku wykonywania.