6

我正在编写一个小型 Angular Web 应用程序,在加载数据时遇到了问题。我使用 Firebase 作为数据源,发现 AngularFire 项目听起来不错。但是,我无法控制数据的显示方式。

起初,我尝试通过执行以下操作来使用常规隐式同步:

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

当我在视图中使用模型 $items 时,它运行良好并且所有数据都显示出来了。但是,当数据来自 Firebase 数据源时,它的格式不是视图支持的方式,因此我需要在数据显示之前对数据进行一些额外的结构更改。问题是,我不知道数据何时已完全加载。我尝试将 $watch 分配给 $items,但它被调用得太早了。

所以,我继续前进并尝试使用 angularfireCollection 代替:

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

文档不太清楚“optionalCallbackOnInitialLoad”的作用和调用时间,但尝试访问 $items 集合中的第一项将引发错误(“Uncaught TypeError: Cannot read property '0' of undefined”) .

我尝试添加一个按钮,并在按钮的单击处理程序中记录了 $items 中第一项的内容,并且它起作用了:

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

就在那里!我的 Firebase 中的第一个对象显示时没有任何错误……唯一的问题是我必须单击一个按钮才能到达那里。

那么,有谁知道我如何知道所有数据何时已加载,然后将其分配给 $scope 变量以显示在我的视图中?还是有其他方法?

我的控制器:

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

我的观点:

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

提前致谢!

4

3 回答 3

2

那么,有谁知道我如何知道所有数据何时已加载,然后将其分配给 $scope 变量以显示在我的视图中?还是有其他方法?

请记住,所有 Firebase 调用都是异步的。您的许多问题正在发生,因为您试图访问尚不存在的元素。按钮单击对您起作用的原因是因为您在成功加载按钮后单击了按钮(并访问了元素)。

在 的情况下optionalCallbackOnInitialLoad,这是一个将在 的初始加载angularFireCollection完成后执行的函数。顾名思义,它是可选的,这意味着如果您不想提供回调函数,则不必提供。

您可以使用它并指定加载后要执行的函数,也可以使用$qPromise 或您喜欢的其他 Promise 库。我自己偏爱 kriskowal 的 Q。我建议阅读一些关于异步 JavaScript 的内容,以便对其中一些问题有更深入的了解。

请注意:

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

确实正确指定了回调函数,但$scope.items直到您运行回调之后才被分配。所以,它仍然不会存在。

如果您只想查看何时$scope.items加载,您可以尝试以下操作:

$scope.$watch('items', function (items) {
    console.log(items)
});
于 2013-09-22T16:47:14.850 回答
1

在我的项目中,我还需要知道数据何时加载。我使用了以下方法(隐式绑定):

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

当 $scope.auctionsDiscoveryPromise 承诺得到解决时,我正在广播一个事件 AUCTION_INIT 正在我的指令中监听。我使用一个短暂的超时,以防某些服务或指令尚未初始化。

于 2013-09-23T07:40:47.543 回答
0

如果它可以帮助任何人,我正在使用它:

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;

}
于 2013-11-22T16:18:39.363 回答