Firebase - Angular $ on listener在回调时返回数据未定义的值

时间:2014-04-14 00:33:16

标签: javascript angularjs firebase promise

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

我使用已加载因为我需要它才能触发一次。我尝试了价值,但感到羞耻。

我想我今天已经耗尽了所有的精力,所以第二种意见会很棒。

P.S。我真的很想知道他们为什么不使用承诺而不是回调。

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

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

3 个答案:

答案 0 :(得分:1)

好的,最后&#34;发现&#34;解决方案。感谢kato提醒我检查我的版本。

当前版本0.7.2预览适用于我。事情是,这还没有凉亭,我认为我从凉亭更新时有最新版本。这是错的。

      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更新,因为该项目似乎比它的凉亭注册表更快。

干杯,玩得开心。

答案 1 :(得分:0)

另一个想到要记住的是这个

            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(匹配的DB引用)与我期望从firebase中获得的对象合并。

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

你实际上可以解决这个问题。但是如何在回调中将结果用作promise deferred.resolve?

我能理解他们这样做是为了能够做到

$ scope.match = $ matchDB。$ on(&#39; loaded&#39;,function(){});

但这并不符合我的目的,即将firebase与我的控制器分离,我并不认为它实际上是一个简洁的解决方案。

请不要接受此作为解决方案,因为它不是真正的解决方案。你可以破解你的方式,但可能有更好的方法,或者至少项目太年轻,很快就会有适当的解决方案。

答案 2 :(得分:0)

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

$ on处理程序中的行336ish

336. callback();

改变
336. callback(self._snapshot);

在_wrapTimeout函数add

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

我希望这对你现在有所帮助。我会尽力为此找到合适的解决方案。