2013-09-22 12 views
5

Ich schreibe eine kleine Angular Web-Anwendung und habe Probleme beim Laden der Daten bekommen. Ich benutze Firebase als Datenquelle und finde das AngularFire-Projekt, das gut klingt. Ich habe jedoch Probleme, die Anzeige der Daten zu steuern.angularfireCollection: wissen, wenn die Daten vollständig geladen sind

Zuerst habe ich versucht, die regelmäßige implizite Synchronisation mit, indem Sie:

angularFire(ref, $scope, 'items'); 

Es funktionierte gut und alle Daten angezeigt wurde, als ich das Modell $ Artikel aus meiner Sicht verwendet. Wenn die Daten jedoch von der Firebase-Datenquelle ankommen, werden sie nicht so formatiert, wie es die Ansicht unterstützt. Daher muss ich die Daten vor der Anzeige noch strukturell verändern. Das Problem ist, ich weiß nicht, wann die Daten vollständig geladen wurden. Ich habe versucht, den $ Items eine $ Watch zuzuordnen, aber es wurde zu früh aufgerufen.

So zog ich auf und versuchte, die angularfireCollection zu verwenden, anstatt:

$scope.items = angularFireCollection(new Firebase(url), optionalCallbackOnInitialLoad); 

Die Dokumentation ist nicht ganz klar, was die „optionalCallbackOnInitialLoad“ tut und wenn sie aufgerufen wird, sondern versucht, das erste Element zuzugreifen in der $ items-Sammlung wird einen Fehler auslösen ("Uncaught TypeError: Kann die Eigenschaft '0' von undefined nicht lesen").

Ich habe versucht, das Hinzufügen einer Schaltfläche und in der Click-Handler der Schaltfläche angemeldet ich den Inhalt des ersten Elements der Elemente $, und es arbeitete:

console.log($scope.items[0]); 

Es wurde! Das erste Objekt aus meiner Firebase wurde ohne Fehler angezeigt ... Das Problem ist nur, dass ich auf eine Schaltfläche klicken musste, um dorthin zu gelangen.

So, weiß jemand, wie ich wissen kann, wenn alle Daten geladen wurde und dann es auf eine Variable $ Rahmen zuweisen meiner Ansicht angezeigt werden? Oder gibt es einen anderen Weg?

Mein Controller:

app.controller('MyController', ['$scope', 'angularFireCollection', 
    function MyController($scope, angularFireCollection) { 
    $scope.start = function() 
    { 
     var ref = new Firebase('https://url.firebaseio.com/days'); 
     console.log("start"); 

     console.log("before load?"); 

     $scope.items = angularFireCollection(ref, function() 
     { 
      console.log("loaded?"); 
      console.log($scope.items[0]); //undefined 
     }); 

     console.log("start() out");  
    }; 

    $scope.start(); 

    //wait for changes 
    $scope.$watch('items', function() { 
     console.log("items watch"); 
     console.log($scope.items[0]); //undefined 
    }); 

    $scope.testData = function() 
    { 
     console.log($scope.items[0].properties); //not undefined 
    }; 
    } 
]); 

Meine Ansicht:

<button ng-click="testData()">Is the data loaded yet?</button> 

Vielen Dank im Voraus!

+0

versuchen, dieses: angularFireCollection (ref, Funktion (Daten) { $ scope.items = data; console.log ($ Umfang. Artikel [0]); }); –

Antwort

2

So, does anyone know how I can know when all the data has been loaded and then assign it to a $scope variable to be displayed in my view? Or is there another way?

Denken Sie daran, dass alle Firebase-Aufrufe asynchron sind. Viele Ihrer Probleme treten auf, weil Sie versuchen, auf Elemente zuzugreifen, die noch nicht existieren. Der Grund für das Klicken auf die Schaltfläche war, dass Sie auf die Schaltfläche geklickt haben (und auf die Elemente zugegriffen haben), nachdem sie erfolgreich geladen wurden.

Im Falle der optionalCallbackOnInitialLoad ist dies eine Funktion, die ausgeführt wird, sobald die anfängliche Belastung der angularFireCollection beendet ist. Wie der Name schon sagt, ist es optional, was bedeutet, dass Sie keine Callback-Funktion bereitstellen müssen, wenn Sie nicht möchten.

Sie können entweder dies verwenden und eine Funktion angeben, die nach dem Laden ausgeführt werden soll, oder Sie können $q Versprechen oder eine andere Versprechen Bibliothek Ihrer Wahl verwenden. Ich bin teilweise auf kriskowal's Q mich. Ich würde vorschlagen, ein wenig über asynchrones JavaScript zu lesen, damit Sie ein tieferes Verständnis für einige dieser Probleme bekommen.

vorsichtig sein, dass dies:

$scope.items = angularFireCollection(ref, function() 
     { 
      console.log("loaded?"); 
      console.log($scope.items[0]); //undefined 
     }); 

korrekt eine Callback-Funktion nicht angeben, aber $scope.items zugewiesen bekommen erst nach Sie den Rückruf laufen habe. Also, es wird immer noch nicht existieren.

Wenn Sie wollen einfach nur sehen, wenn $scope.items geladen ist, könnten Sie so etwas wie dies versuchen:

$scope.$watch('items', function (items) { 
    console.log(items) 
}); 
+0

Hallo und danke! Der Rückruf hat ein "Ergebnis", aber er enthält meine Daten nicht, so dass ich nicht wirklich weiß, was es ist. Würde es Ihnen etwas ausmachen, ein einfaches Beispiel für die Implementierung des $ q-Versprechens hier zu geben? Ich habe Probleme zu verstehen, wie man es in diesem Zusammenhang benutzt. – iafiawik

+0

@iafiawik Wenn Sie dies nur zu Debuggingzwecken tun möchten, könnten Sie '$ scope. $ Watch' verwenden, was ich jetzt in einem kurzen Beispiel oben gezeigt habe. –

1

In meinem Projekt auch ich musste wissen, wenn die Daten geladen wurden. Ich benutzte den folgenden Ansatz (implizite Bindungen):

$scope.auctionsDiscoveryPromise = angularFire(firebaseReference.getInstance() + "/auctionlist", $scope, 'auctionlist', []); 

$scope.auctionsDiscoveryPromise.then(function() { 
    console.log("AuctionsDiscoverController auctionsDiscoveryPromise resolved"); 
    $timeout(function() { 
     $scope.$broadcast("AUCTION_INIT"); 
    }, 500); 

}, function() { 
    console.error("AuctionsDiscoverController auctionsDiscoveryPromise rejected"); 
}); 

Wenn die $ scope.auctionsDiscoveryPromise Versprechen gelöst wurde ich sendet ein Ereignis AUCTION_INIT, die in meine Richtlinien gehört wird. Ich verwende eine kurze Zeitüberschreitung für den Fall, dass einige Dienste oder Anweisungen noch nicht initialisiert wurden.

0

Ich verwende dieses, wenn es jemand helfen würde:

function getAll(items) { 

    var deferred = $q.defer(); 
    var dataRef = new Firebase(baseUrl + items); 
    var returnData = angularFireCollection(dataRef, function(data){ 
      deferred.resolve(data.val()); 
    }); 
    return deferred.promise; 

} 
Verwandte Themen