从 Firebase 的 DataSnapshot 列出数组的项目时,应用程序首次加载失败

App Fails First Load When Listing Array's Item from a DataSnapshot from Firebase

我正在将 DataSnapshot 存储到 $scope 数组中,因此 ng-repeat 到 HTML div 更新了我的 "result list"

问题是,当我 运行 代码,输入一个值并点击 运行 DataSnapshot 函数时,第一个结果没有出现在应用程序屏幕上,只出现在应用程序的登录浏览器的控制台。如果我再次 运行 该函数,结果就会出现。如果我更改输入并再次单击按钮(运行 函数),则此输入会在第一次尝试时出现。

那么,这就是您可能需要的东西:

从第一次尝试打印(数据出现在控制台上但不在应用程序上): 第二次尝试打印(数据在控制台上出现两次,在应用程序上出现一次): 第三次尝试使用另一个输入进行打印(数据在控制台上出现一次,在应用程序上出现一次):

代码:

index.html

<div class="list card">
    <div class="item item-body" ng-repeat="locker in lockers">
    <a  href="#" class="item item-icon-right text-center">
    <img ng-src="{{imageSrc}}" style="width: 35px; height: auto;"> 
    <p style="text-align: center">  
     Locker - {{locker.number}}
     <br>
     {{key}}                     
    </p>
    <i class="icon ion-chevron-right"></i>  
      </a>

    </div>

app.js

angular.module('starter', ['ionic', 'firebase'])

.controller('LockerCtrl', ["$scope", "$firebaseArray", function($scope,$firebaseArray, snapshot){
var lockersRef = new Firebase('https://ifrjarmariosdb.firebaseio.com/armarios');



$scope.getButtonClicked = function() {
  var lockernumber = document.getElementById('lockerNumberInput').value;
  if(lockernumber.length > 0){
    lockerInputedNumber = parseInt(lockernumber); 
    lockersRef.on('value', function(snapshot){ 

      snapshot.forEach(function(data){
        var number = data.val().number;

        if(number == lockerInputedNumber){ 
          $scope.key = data.key(); 
          $scope.lockers = [data.val()];
          console.log(data.val()); 

          if(number == 101){ -
            $scope.imageSrc = "img/locker_test2.png";
          }
          else{
            $scope.imageSrc = "img/locker_test.jpg";
          }
        }
      });
    });
  }

正如您从照片中看到的那样,我在根据 Firebase 的数值更改图像源时也遇到了一些麻烦。如果你能帮我解决这个问题,那将是一个很大的帮助。

拜托,我不是在寻求此方法的解决方案,如果您知道其他方法,我也请您post。

谢谢!

此代码开始从 Firebase 加载数据:

lockersRef.on('value', function(snapshot){ 

  snapshot.forEach(function(data){
    var number = data.val().number;

    if(number == lockerInputedNumber){ 
      $scope.key = data.key(); 
      $scope.lockers = [data.val()];
      console.log(data.val()); 

      if(number == 101){ -
        $scope.imageSrc = "img/locker_test2.png";
      }
      else{
        $scope.imageSrc = "img/locker_test.jpg";
      }
    }
  });

加载是异步发生的。由于数据可用之前需要时间,因此浏览器继续执行 JavaScript after 这段代码。

当数据从服务器返回时,它会执行您的回调函数。但在那一点上,AngularJS 不再期望对 $scope.

进行任何更改

解决方案是让 AngularJS 知道您已经更改了范围。最简单的方法是将回调包装到 $timeout() 调用中:

lockersRef.on('value', function(snapshot){ 
  $timeout(function() {
    snapshot.forEach(function(data){
      var number = data.val().number;

      if(number == lockerInputedNumber){ 
        $scope.key = data.key(); 
        $scope.lockers = [data.val()];
        console.log(data.val()); 

        if(number == 101){ -
          $scope.imageSrc = "img/locker_test2.png";
        }
        else{
          $scope.imageSrc = "img/locker_test.jpg";
        }
      }
    });
  });

有些人 运行 遇到了同样的问题:

关于您的代码我注意到的其他几点:

  • 您正在下载所有储物柜,然后过滤用户在客户端输入的储物柜。这是在浪费您的用户可能要付费的带宽。更好的方法是使用 Query:

    将过滤留给 Firebase
    var query = lockersRef.orderByChild('number').equalTo(lockerInputedNumber);
    query.on('value', function(snapshot){ 
    
  • AngularJS+Firebase 有一个名为 AngularFire 的绑定库,它会自动处理 $timeout() 事情。它建立在您现在使用的 Firebase JavaScript SDK 之上,因此它们可以完美地互操作。