尝试从工厂中的 ref.on() 返回值到控制器

Trying to return value from ref.on() in factory to controller

本文关键字:返回值 控制器 on ref 工厂      更新时间:2023-09-26

我正在尝试从工厂中的Firebase查询中检索值到我的控制器,但没有成功。有人有想法吗??

控制器:

main.controller("mainCtrl", function($scope, totalusers){
  $scope.city = "whatever";
  $scope.total = totalusers.getusers($scope.city);
});

工厂(我在其中查询以检索有多少用户指定了名称):

app.factory("totalusers", function(FURL) {
    var gettotalusers      = {};
    gettotalusers.getusers = function(city) {
        var tusers = new Firebase(FURL + "/Users/" + city);
        var count  = 0;
        tusers.on("value", function(snapshot) {
            snapshot.forEach(function(child) {
                if (child.val().Name != undefined) {
                    count++;
                }
            });
            var total = count;
            return total;
        });
    }
    return gettotalusers;
});

任何线索都会很棒,谢谢;)

访问 Firebase 值是异步完成的,因此当计数值分配给total时,计数值仍为 0,然后立即返回。您可以使用$q服务创建承诺,并在 Firebase 回调返回时解决该承诺

app.factory("totalusers", function(FURL, $q){
  var gettotalusers = {};
  gettotalusers.getusers = function(city){
    var tusers = new Firebase(FURL + "/Users/" + city);
    var count = 0;
    var deferred = $q.defer();
    tusers.on("value", function(snapshot){
      snapshot.forEach(function(child) {
        if(child.val().Name != undefined){
          count++;
        }
      });
      deferred.resolve(count);
    });
    return deferred.promise;
  }
  return gettotalusers;
});

然后在控制器中,您无法直接分配结果。您需要在承诺处理程序方法中执行此操作,如下所示:

main.controller("mainCtrl", function($scope, totalusers){
  $scope.city = "whatever";
  totalusers.getusers($scope.city).then(
    function(total) {
      $scope.total = total;
    },
    function(err) {
      // handle error
    }
  );
});

有关更多详细信息,请参阅$q文档并阅读承诺的概念。https://docs.angularjs.org/api/ng/service/$q

您还可以尝试使用过滤器和减少以更实用的方式写入计数:

var total = snapshot
  .filter(function(item) { return child.val().Name !== undefined })
  .reduce(function(acc, curr) {
    return acc + curr;
  }
);

在这种情况下使用 ref.on() 是一个坏主意,因为即使在函数完成后,它也会继续同步该节点。您应该调用ref.off(),或者更简单地说,使用 ref.once() 。如果您使用的是最新版本的 Firebase,这将返回一个承诺,这意味着您不需要$q

app.factory("totalusers", function(FURL) {
    var gettotalusers = {};
    gettotalusers.getusers = function(city) {
        var tusers = new Firebase(FURL + "/Users/" + city);
        return tusers.orderByChild("Name")
                     .startAt(false)
                     .once("value")
                     .then(function(snapshot) {
            return snapshot.numChildren();
        });
    };
    return gettotalusers;
});