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

时间:2013-10-16 03:48:58

标签: angularjs firebase angularfire

我正在尝试将Firebase和AngularFire用于我正在构建的应用。我无疑是角度和Firebase的新手,所以任何帮助都会受到赞赏。

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

  • EPICS
    • 史诗1
      • 编号
      • 标题等
    • 史诗2
      • 编号
      • 标题等
  • USERS

    • 用户1

      -activeepics

      • 活跃的史诗1

      • 活跃的史诗2

在下一页上,我对数据库中的每个史诗都有一个ng-repeat。每个史诗都有一排按钮,其中一个给我带来麻烦。如果当前用户已经开始史诗(例如,史诗出现在该用户的“activeepics”中),则按钮应该说“点击”。如果史诗不在用户的主动视觉中,则应显示“开始”。

单击按钮时,按钮应执行不同的操作,具体取决于按钮标签。因此,如果按钮标签显示“开始”,则应用应将史诗添加到当前用户“activeepics”中,并将按钮标签更改为“Tap Out”。相反,如果按钮标签为“Tap Out”,应用程序应从“activeepics”中删除史诗,并将按钮标签更改回“Start”。

然而,我得到各种奇怪的行为。当我使用虚拟身份证(例如1或0)时,应用程序会显示正确的按钮标签。但是,当我添加带有Firebase生成ID的史诗时,所有标签都会重置为“开始”。我也注意到应用程序循环遍历每个史诗多次(我为每个史诗显示进入调试console.log)。

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

以下是代码:

查看

<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);
                    }
                }
            });
        });

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

首先回答您的直接问题:

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

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

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

    目前,您的迭代未运行,所有内容都恢复为"Start"

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

    这是AngularJS观察系统的一个功能,因为你的视图正在调用一个方法然后改变视图,所以手表再次运行,再次触发该方法(稍微粗略地说),依此类推等等对于所有需要标签的史诗。有关更好的解释,请参阅this SO answer

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