2013-09-22 8 views
5

Piszę małą aplikację internetową Angular i mam problemy z ładowaniem danych. Używam Firebase jako źródła danych i znalazłem projekt AngularFire, który brzmiał ładnie. Mam jednak problem z kontrolowaniem sposobu wyświetlania danych.angularfireCollection: wiem, kiedy dane są w pełni załadowane

Początkowo próbowałem za pomocą regularnej synchronizacji niejawny wykonując:

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

To działało w porządku, a wszystkie dane wyświetlane kiedy stosuje model $ items moim zdaniem. Jednak gdy dane docierają ze źródła danych Firebase, nie są one sformatowane w taki sposób, jaki obsługuje widok, więc muszę wprowadzić dodatkowe zmiany strukturalne danych przed ich wyświetleniem. Problem polega na tym, że nie wiem, kiedy dane zostały w pełni załadowane. Próbowałem przypisać zegarek $ do pozycji $, ale został on wywołany zbyt wcześnie.

Więc przeniósł się i starał się wykorzystać angularfireCollection Zamiast:

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

dokumentacja nie jest jasne, co „optionalCallbackOnInitialLoad” czy i kiedy to się nazywa, ale próbuje uzyskać dostęp do pierwszego elementu w kolekcji $ items pojawi się błąd ("Uncaught TypeError: Can not read property" 0 "of undefined").

Próbowałem dodanie przycisku i kliknij przycisk obsługi w Zalogowałem treść pierwszej pozycji w $ przedmiotów, a pracował:

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

Nie było! Pierwszy obiekt z mojej Bazy Firebase został wyświetlony bez żadnych błędów ... Jedynym problemem było to, że musiałem kliknąć przycisk, aby się tam dostać.

Więc, czy ktoś wie jak mogę wiedzieć kiedy wszystkie dane zostały załadowane i następnie przypisać ją do zmiennej zakres $ mają być wyświetlane w moim zdaniem? A może jest inny sposób?

Mój kontroler:

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

moim zdaniem:

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

Z góry dzięki!

+0

spróbuj tego: angularFireCollection (ref, funkcja (dane) { $ scope.items = dane; console.log ($ zakres. items [0]); }); –

Odpowiedz

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?

Pamiętaj, że wszystkie połączenia z Firebase są asynchroniczne. Wiele z twoich problemów pojawia się, ponieważ próbujesz uzyskać dostęp do elementów, które jeszcze nie istnieją. Powodem, dla którego kliknięcie przycisku zadziałało, jest to, że kliknąłeś przycisk (i uzyskałeś dostęp do elementów) po ich pomyślnym załadowaniu.

W przypadku optionalCallbackOnInitialLoad jest to funkcja, która zostanie wykonana po zakończeniu ładowania początkowego angularFireCollection. Jak sama nazwa wskazuje, jest to opcjonalne, co oznacza, że ​​nie musisz dostarczać funkcji zwrotnej, jeśli nie chcesz.

Możesz użyć tego i określić funkcję do wykonania po załadowaniu lub możesz użyć obietnic $q lub innej obiecującej biblioteki, która Ci się podoba. Jestem stronniczy pod adresem kriskowal's Q. Proponuję trochę przeczytać asynchroniczny JavaScript, aby lepiej zrozumieć niektóre z tych problemów.

Bądź ostrożny, że:

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

ma prawidłowo określić funkcję oddzwonienia, ale $scope.items nie zostanie przydzielony aż po pan prowadził zwrotnego. Tak więc nadal nie będzie istnieć.

Jeśli chcesz tylko zobaczyć, kiedy $scope.items został załadowany, można spróbować czegoś takiego:

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

Cześć i dzięki! Callback ma "wynik", ale nie zawiera moich danych, więc nie wiem, co to jest. Czy mógłbyś podzielić się prostym przykładem, jak wdrożyć obietnicę $ Q tutaj? Mam problem ze zrozumieniem, jak go używać w tym kontekście. – iafiawik

+0

@iafiawik Jeśli chcesz to zrobić tylko w celu debugowania, możesz użyć '$ scope. $ Watch', który pokazałem już w szybkim przykładzie powyżej. –

1

w moim projekcie Musiałem wiedzieć też, gdy dane zostały załadowane. Kiedyś następujące podejście (ukryte powiązań):

$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"); 
}); 

Gdy obietnica $ scope.auctionsDiscoveryPromise został rozwiązany jestem emisją AUCTION_INIT wydarzenie, które jest słuchał moich dyrektyw. Używam krótkiego limitu czasu na wypadek, gdyby niektóre usługi lub dyrektywy nie zostały jeszcze zainicjalizowane.

0

Używam tego, jeśli to pomoże każdemu:

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; 

} 
Powiązane problemy