使用具有多个承诺的AngularFire获取数据 - 无限循环



我正在尝试将Firebase和AngularFire用于我正在构建的应用程序。诚然,我是 angular 和 Firebase 的新手,所以任何帮助将不胜感激。

我在Firebase中有以下数据库结构:

  • 史诗
    • 史诗 1
      • 编号
      • 标题等
    • 史诗2
      • 编号
      • 标题等
  • 用户

    • 用户 1

      -活性史诗

      • 活跃史诗 1

      • 活跃的史诗2

在下一页上,我对数据库中的每个史诗都有一个ng重复。每个史诗都有一排按钮,其中一个给我带来了麻烦。如果当前用户已经启动了长篇故事(例如,长篇故事出现在该用户的"活动史诗"中),那么按钮应该显示"点击退出"。如果长篇故事不在用户的活动史诗中,则它应显示"开始"。

单击按钮时应执行不同的操作,具体取决于按钮标签。因此,如果按钮标签显示"开始",则应用应将长篇故事添加到当前用户的"活动史诗"中,并将按钮标签更改为"点击退出"。相反,如果按钮标签为"点击退出",则应用应从"活动史诗"中删除长篇故事,并将按钮标签更改回"开始"。

但是,我得到了各种奇怪的行为。当我使用虚拟 ID (例如 1 或 0)时,该应用程序会显示正确的按钮标签。但是,当我添加带有 Firebase 生成 ID 的长篇故事时,所有标签都会重置为"开始"。我还注意到该应用程序正在多次循环浏览每个史诗(我为显示的每个史诗进入了调试控制台.log)。

我认为问题可能是将Firebase数据绑定到$scope后我有多个承诺对象。如果可以的话,请帮忙!

这是代码:

视图

<div ng-repeat="(name,epic) in epics | filter:search | orderBy:order | filter:{category:category}" class="epic">
        <div>
                <div class="small-block-grid-3 epicActions">
                    <li><a href="#"> Remix </a></li>
                    <li><a href="#/share"> Share </a></li>
                    <li><a href="#" ng-click="handleLabel(name)" prevent> {{getLabel(name)}} </a></li>
                </div>
            </ul>
        </div>  
    </div>

控制器

$scope.desiredUser = UserService.getCurrentUser();
        var ref = new Firebase("https://epicly.firebaseio.com/epics");
        angularFire(ref, $scope, 'epics');
        var ref2 = new Firebase("https://epicly.firebaseio.com/users");
        angularFire(ref2, $scope, 'users').then(function(){
                for (var i = 0; i<$scope.users.length; i++){
                    if($scope.users[i].email === $scope.desiredUser){
                        $scope.currUser = $scope.users[i];
                    }
                }

            var ref3 = new Firebase("https://epicly.firebaseio.com/users/" + $scope.currUser.id + "/activeepics");
            angularFire(ref3, $scope, 'activeEpics').then(function(){
                console.log($scope.activeEpics);
                $scope.getLabel = function(epic){
                    console.log(epic);
                    for(var i = 0; i < $scope.activeEpics.length; i++){
                        if ($scope.activeEpics[i].id === epic) {
                            return "Tap Out";
                        } 
                    }
                    return "Start";
                }   
                $scope.handleLabel = function(name){
                    var label = $scope.getLabel(name);
                    if(label === "Tap Out"){
                        //remove from active epics
                    } else {
                        //add to activeepics
                        $scope.toAdd = {"id": name}
                        $scope.activeEpics.push($scope.toAdd);
                    }
                }
            });
        });

首先回答您的直接问题:

  1. 为什么添加epic时所有标签都重置为 "Start"

    您的$scope.getLabel方法是尝试遍历$scope.activeEpics,这是angularFire承诺的结果。但是$scope.activeEpics是一个对象,而不是一个数组,所以它没有索引或.length属性。即使有,假设的结果数组元素也不会具有您期望的id属性。相反,您正在寻找activeEpic引用的name(),以与epic引用的name()进行比较。这实际上简化了您的生活,因为您只想知道activeEpics对象中是否存在给定的epic名称,因此该方法可能如下所示:

    $scope.getLabel = function(epicName){
      var labelText = $scope.activeEpics[epicName] ? "Tap Out" : "Start";
      return labelText;
    }
    

    就目前而言,您的迭代没有运行,一切都会恢复到"Start"

  2. 为什么您的$scope.getLabel函数执行这么多次?

    这是 AngularJS 监视系统的一个函数,因为您的视图正在调用一个方法,然后更改视图,因此手表再次运行,再次触发该方法(粗略地说),依此类推,对于所有需要标签的史诗。请参阅此SO答案以获取更好的解释。

如果我可以提供一些一般性建议,看起来您正在尝试以某种迂回的方式通过他们的电子邮件找到用户。您可以尝试使用 Firebase 优先级系统更优雅地完成相同的操作,如此处所述。如果您收紧格式并全面使用更明确的变量和参数命名,那么遵循代码也会更容易。只有我的两分钱。祝你好运!

我认为您的部分问题可能是您正在尝试遍历一个对象,就好像它是一个数组一样。如果您使用连续的数字 ID(0、1 等)在 Firebase 中存储数据AngularFire会将您的数据视为一个数组。如果您使用键(例如使用 Firebase.push() 创建的键),AngularFire 会将您的数据视为键和值的字典。

我会提前指定您希望angularFire变量的数据类型,因此在调用AngularFire()之前插入$scope.users = []$scope.activeEpics = {},或者任何情况,然后检查对象以查看它们实际上是字典还是数组,并适当地更改迭代方法。

最新更新