2016-04-04 9 views
0

In meiner index.html-Datei habe ich eine appController, die wie eine main controller ist, die einige Grundeinstellungen im $ rootScope laden muss, damit ich kann Verwenden Sie diese Einstellungen in der child controllers(Data-Ui-View = Ui-Router-Plugin).

<body ng-controller="appController"> 

    <div data-ui-view></div> 

</body> 

Im appController ich verwende einen Dienst (appService), wo ich Daten aus der Datenbank erhalten und setze einen Bruchteil dieser Daten in einer $ rootScope Eigenschaft formData

appService.formData() 
.then(function(data) { 
    $rootScope.formData = data[0].num; 
    if ($rootScope.formData) { 
     $rootScope.$broadcast('afterFormDataLoaded'); 
    } 
}) 

Es ist sehr wichtig, dass andere (untergeordnete) Controller werden nicht ausgeführt, bevor das $ rootScope.formData mit den tatsächlichen Daten gefüllt wird. So zu tun, dass ich $rootScope.$broadcast in der übergeordneten Steuerung verwenden und:

$scope.$on('afterFormDataLoaded', function() { 
    // the code 
}) 

$scope.$on in den Kinder Controllern.

Das funktioniert! Mein Kind-Controller wird nur ausgeführt, nachdem der $broadcast im Hauptcontroller auf afterFormDataLoaded eingestellt ist.

Aber ich habe Probleme, wenn ich die Ansicht ändere und ich navigiere von einem Kind (View & Controller) zu einem anderen. Es ist klar für mich, dass ich Probleme mit dieser $broadcast Methode haben werde, weil $ broadcast einmal ausgeführt wird, wenn ich die Seite lade/aktualisiere und nicht, wenn ich die Ansicht ändere. So wird $scope.$on nicht ausgelöst, wenn ich die Ansicht ändere.

Was ist die richtige und plausibelste Möglichkeit, alle meine Kindersteuerungen warten zu lassen, bis meine asynchrone Elternfunktion erfolgreich ausgeführt wird und $ rootScope.formData true ist?

Antwort

1

Im UI-Router können Sie einen Auflösungsparameter zur Statusdeklaration hinzufügen (https://github.com/angular-ui/ui-router/wiki#resolve). Damit es funktioniert, müssen Sie das Versprechen speichern, bis es gelöst ist.

Hier ist ein Beispiel

angular.run(['$rootScope', '$q', function($rootScope, $q){ 
    var defer = $q.defer(); 
    var dataPromise = defer.promise; 
    $rootScope.resolveDataPromise = function(data){ 
     defer.resolve(data); 
    } 
}]); 

angular.config(['$stateProvider', function($stateProvider){ 
    $stateProvider.state({ 
     resolve:{ 
      myData:['$rootScope', function($rootScope){ 
       return $rootScope.dataPromise; 
      }] 
     } 
    }); 
}]); 

appService.formData().then(function(data) { 
    if(data[0].num){ 
     $rootScope.resolveDataPromise(data[0].num); 
    } 
}) 

Hinweis: die Daten der Entschlossenheit, erhalten Sie es in Ihrem Controller nur injizieren kann, der Schlüssel des resolve Objekt ist der Name: myData hier.

Sie können es entweder in allen Zustand definieren, die Sie benötigen, oder in einem übergeordneten Zustand, das wird funktionieren.

+0

Vielen Dank für dieses Beispiel. Nur 2 Probleme/Fragen: 1. Ich glaube, Sie haben vergessen, die DataPromise var zu dem $ rootScope hinzuzufügen. Um das zu beheben, habe ich '$ rootScope.dataPromise = dataPromise' nach Zeile 6 hinzugefügt. 2. Wenn $ rootScope verwendet wird, ist es notwendig,' resolve: {} '? Ich kann einfach $ rootscope.dataPromise in meinem Controller verwenden – Peter

+0

1 ja, ich habe vergessen. 2: Wenn Sie wirklich möchten, dass Ihr Status nichts anzeigt, bevor das Versprechen aufgelöst wurde, verwenden Sie resolve: {}. Andernfalls können Sie $ rootScope.dataPromise im Controller verwenden. – Walfrat

0

Sie könnten $ rootScope auf dem entsprechenden Controller referenzieren und in einer Startfunktion lesen, wenn $ rootScope.formData gefüllt ist und wenn Sie Ihren Listener nicht registrieren.

Auch wenn Sie ui-routerresolve verwenden, könnte genau das tun, was Sie wollen.

Verwandte Themen