2013-08-22 10 views
6

Powiem to przed faktem, że naprawdę nie mam pojęcia, czy jest to najlepszy sposób, aby osiągnąć to, co robię i jestem bardzo otwarty na lepsze sugestie.Zapewnienie, że jeden kontroler AngularJS ładuje się przed innym

Mam system konta użytkownika korzystający z OAUTH2, który wyszukuje informacje o użytkowniku w mojej bazie danych i zapisuje je jako zmienną, $rootScope.userInfo. Jest on umieszczony w kontrolerze dołączonym do aplikacji body mojej aplikacji; tutaj myślałem, że kontroler najwyższego poziomu załaduje się przed tymi, którzy w nim mieszkają, ale najwyraźniej nie.

Jeśli załadować widok, który próbuje uzyskać dostęp do tej $rootScope.userInfo przedmiot przed moim mainCtrl miał szansę, aby załadować go z mojej bazy danych, to rzuca javascript błąd i Angular przerwy.

Dla porównania, tutaj jest grubsza od szablonu:

<body ng-controller="mainCtrl"> 
    <header>Content</header> 
    <div class='main-view' ng-controller="userProfile"> 
     <p>{{user.name}}</p> 
     <p>{{user.email}}</p> 
    </div> 
</body> 

Ja ładuje $rootScope.userInfo w mainCtrl tak:

$http.get('/api/users/' + $cookies.id). 
    success(function(data) { 
     $rootScope.userInfo = data.user[0]; 
     console.log("User info is:"); 
     console.log($rootScope.userInfo); 
     $scope.status = 'ready'; 
    }); 

Wtedy mój userProfile kontroli, robię:

function userProfile($scope, $cookies, $http, $routeParams, $rootScope){ 
    if($scope.status == 'ready'){ 
    $scope.user = $rootScope.userInfo; 
    console.log("Double checking user info, here it is:"); 
    console.log($rootScope.userInfo); 
    } 
} 

Jeśli pochodzę z innej strony w aplikacji wh Ich nie dzwoni $rootScope.userInfo, API ma wystarczająco dużo czasu, aby to sprawdzić, a moja strona userProfile działa dobrze. Jednak w przypadku odświeżania całej strony, $rootScope.userInfo nie ma czasu na załadowanie i pojawiają się błędy.

Jak mogę to naprawić?

Odpowiedz

14

Problem, który opisujesz, jest jednym z powodów, dla których nie zaleca się udostępniania danych między kontrolerami przy użyciu $rootScope: tworzy on ręczną "niewidoczną" zależność między dwoma kontrolerami, którą trzeba ręcznie naprawić, gdy użytkownik końcowy nie przeszedł inny kontroler jeszcze.

Zalecanym rozwiązaniem jest przeniesienie logiki ładującej użytkownika do usługi, na przykład userProfileService, którą należy wprowadzić do obu kontrolerów, które jej potrzebują. Zostanie on utworzony jeden raz i użyty dla obu kontrolerów. W takiej usłudze można załadować profil użytkownika za pomocą $http, gdy kontroler go poprosi, i zwrócić go z pamięci podręcznej, gdy następna robi. W ten sposób zależność przechodzi z obu kontrolerów do usługi wspólnej, a nie z jednego kontrolera do drugiego.

Nie jestem wielkim fanem dokumentacji AngularJS, ale te mogą pomóc: DI, Creating Services i Injecting Services.

+0

Jest to bardzo blisko, podoba mi się pomysł wykorzystania go jako usługi. Jednak nie rozwiązuje problemu z ładowaniem. Mam usługę skonfigurowaną, ale wciąż ładuje kontroler zanim usługa zwróci jakiekolwiek dane! pomysły? – Jascination

+0

Mam zaktualizowane pytanie tutaj: http://stackoverflow.com/questions/18477711/force-angularjs-service-to-return-data-before-loading-controller Przyjmę to jako odpowiedź, tak jak to robi większość pracy, ale nie wahaj się odpowiedzieć na to pytanie. – Jascination

0

Zastosowanie then zamiast sukcesu i opóźnić ładowanie kontrolera dziecięcej używając ng-include:

<body ng-controller="mainCtrl"> 
    <header>Content</header> 
    <ng-include src="templatePath"></ng-include>   
</body> 

Przesuń HTML wewnątrz nowego szablonu userprofile.html:

<div class='main-view' ng-controller="userProfile"> 
    <p>{{user.name}}</p> 
    <p>{{user.email}}</p> 
</div> 

zwrotnego wewnątrz mainCtrl:

$http.get('/api/users/' + $cookies.id). 
    then(function(data) { 
     /* mainCtrl being the parent controller, simply exposing the 
      properties to $scope would make them available 
      to all the child controllers.*/ 
     $rootScope.userInfo = data.user[0]; 
     /* assign the template path to load the template and 
      instantiate the controller */ 
     $scope.templatePath = "userprofile.html"; 
    }); 
+0

'$ http.success (foo)' jest aliasem '$ http.then (foo)', który poprawnie przekazuje wszystkie argumenty.Co zmieniłoby przejście 'success' na' then'? Zobacz [źródło] (https://github.com/angular/angular.js/blob/master/src/ng/http.js#L673). –

+0

@stevuu Tak. Wydaje się, że nie ma sensu korzystać z jednego nad drugim. – AlwaysALearner

Powiązane problemy