监听器上的Angular$在回调时返回未定义的数据值

Firebase - Angular $on listener returns data undefined value on callback

本文关键字:返回 未定义 数据 Angular 监听器 回调      更新时间:2023-09-26

我正在尝试从firebase中获取一些数据,我正在使用angular firebase插件。我在检查器中仔细检查了调试,url是正确的。它会返回,这意味着url是正确的,但回调的参数是未定义的。

我正在使用loaded,因为我需要它发射一次。我尝试了有价值但有羞耻感的东西。

我想我今天已经把所有的精力都用在了这件事上,所以再发表一个意见就好了。

附言:我真的很奇怪他们为什么不使用承诺而不是回调。

来自angular+firebase工厂的碎片

     var seekMatch = function(player) {
        var deferred = $q.defer();
        
        angular.forEach(matches.$getIndex(), function(matchId) {
            var matchRef = firebaseRef('matches/' + matchId);  // <-- double checked, the url sends me to the correct firebase record
            var matchDB = $firebase(matchRef);
            
            matchDB.$on('loaded', function(data) {
                console.log(data);   // <----- return's undefined
                if (matchMakingFormula(data.playerA, player)) {
                    if (!match) {
                        match = data;
                        deferred.resolve(match);
                    }
                }
            });
        });
        
        return deferred.promise;
    };

我在这里添加所有代码是为了让你更好地了解我要做的事情。

我的fb.match.service的完整代码

'use strict';
angular.module('angularfireApp')
.factory('FBmatchService', ['$rootScope' , '$q', '$firebase', 'firebaseRef',
function ($rootScope, $q, $firebase, firebaseRef) {
  // Service logic
  var matchesRef = firebaseRef( '/matches/' );
  var matches = $firebase(matchesRef);
  var match = null;
  var matchMakingFormula = function (playerA , playerB) {
    return playerA.type !== playerB.type
    && distanceFormula( playerA.location.lat , playerA.location.long, playerB.location.lat , playerB.location.long ) < 1
  };
  var distanceFormula = function (lat1 , lon1 , lat2, lon2) {
    var R = 6371; // km
    var dLat = (lat2-lat1).toRad();
    var dLon = (lon2-lon1).toRad();
    var lat1 = lat1.toRad();
    var lat2 = lat2.toRad();
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    return d;
  };
  var getMatch = function (matchId) {
    match = matches.$getIndex(matchId);
    return match;
  };
  var seekMatch = function ( player ) {
    var deferred =  $q.defer();
    angular.forEach(matches.$getIndex() , function (matchId){
      var matchRef = firebaseRef( 'matches/'+matchId );
      var matchDB = $firebase( matchRef );
      matchDB.$on('loaded',function (data) {
        console.log(data);
        if (matchMakingFormula(data.playerA , player)) {
          if (!match) {
            match = data;
            deferred.resolve(match);
          }
        }
      });
    });
    return deferred.promise;
  };

  // Public API here
  return {
    get: function (matchId) {
      return getMatch(matchId);
    },
    seek: function (points) {
      return seekMatch(points);
      //return match.promise;
    },
    new: function (points) {
      //return match.promise;
    },
    join: function (match) {
      //return match;
    }
  };
}]);

提前谢谢。干杯,玩得开心!

好了,终于"找到"了解决方案。感谢kato提醒我检查我的版本。

目前0.7.2版本的预览版对我来说很有效。问题是它还没有在bower上,我认为我在bower更新时有最新版本。这是错误的。

      collection.$child( matchId ).$on('loaded' , function(match){  //<---- match now returns the proper object but also null or {} empty object sometimes if empty.
        if (match) {
          if (valid(match)){ //<-- so you need to validate the output not just !match
            deferred.resolve(match); 
          }
          else
          {
            deferred.reject('invalid');
          }
        }
        else
        {
          deferred.reject('no match');
        }
      });

无论哪种方式,在出于恢复和错误捕获的原因使用端点之前验证端点总是一个好主意。

github的更新效果更好,因为该项目的进展似乎比bower注册表快得多。

干杯,玩得开心。

我在angularfire.js 中用一个小黑客修复了这个问题

$on处理程序中的第336ish行

336. callback();

变更

336. callback(self._snapshot);

_wrapTimeout函数末尾的第587ish行添加

  587. //hack to preserve the snapshot from the timeout wipeouts
  if ( evt === "loaded" ) {
    self._snapshot = param;
  }

我希望这对你现在有所帮助。我会设法找到一个合适的解决方案。

需要记住的另一个想法是

            matchDB.$on('loaded', function(data) {
                console.log(matchDB);  //  <--- notice what is going on here
                if (matchMakingFormula(data.playerA, player)) {
                    if (!match) {
                        match = data;
                        deferred.resolve(match);
                    }
                }
            });

这是吗

matchDB: Object
 $add: function (item) {
 $auth: function (token) {
 $bind: function (scope, name) {
 $child: function (key) {
 $getIndex: function () {
 $off: function (type, callback) {
 $on: function (type, callback) {
 $remove: function (key) {
 $save: function (key) {
 $set: function (newValue) {
 $transaction: function (updateFn, applyLocally) {
 playerA: Object  //  <----  notice this. it was the content of the object in firebase
 __proto__: Object

这太疯狂了。。。它实际上是将matchDB(match的DB引用)与我期望从firebase中得到的对象进行合并。

 "13131314141"{
    "playerA" : {
       "location" : {
           "lat" : 51.6021821,
           "long" : "-02582276"
        },
        "type" : "monster"
    }
 }

你实际上可以从中找到解决方案。但是,如何将回调中的结果用作promise deferred.resolve呢?

我可以理解他们这样做是为了能够进行

$scope.match=$matchDB$on('loaded',function(){});

但这不符合我的目的,即将firebase与我的控制器解耦,我真的不认为这实际上是一个巧妙的解决方案。

请不要接受这是一个解决方案,因为它不是一个真正的解决方案。你可以破解你的方法使其成为一个,但可能有更好的方法来做到这一点,或者至少这个项目还太年轻,很快就会有合适的解决方案。