【问题标题】:Cannot get data from firebase in directive angularjs无法从指令 angularjs 中的 firebase 获取数据
【发布时间】:2014-11-19 10:39:15
【问题描述】:

我正在使用 Angular.js 和 Firebase API 按照this tutorial 中的步骤制作滑块。

我在指令文件中创建了一个指令“滑块”,代码如下:

.directive('slider', function()
{
    return {
        restrict: 'E',
        replace: true,
        link: function(scope, elem, attrs) {
            scope.currentIndex = 0; // Initially the index is at the first slide

            scope.next = function()
            {
                scope.currentIndex < scope.challenges.length - 1 ? scope.currentIndex++ : scope.currentIndex = 0;
            };

            scope.prev = function()
            {
                scope.currentIndex > 0 ? scope.currentIndex-- : scope.currentIndex = scope.challenges.length - 1;
            };

            scope.$watch('currentIndex', function()
            {
                scope.challenges.forEach(function(challenge)
                {
                    challenge.visible = false; // make every challenge invisible
                });

                scope.challenges[scope.currentIndex].visible = true; // make the current challenge visible
            });
        },
        template: '<div></div>'
    };

如您所见,我没有隔离范围,因此它应该从父级获取 scope.challenges,但它作为未定义的值而不是来自 Firebase 的数据。

这样做 forEach of undefined 会引发错误: TypeError:无法读取未定义的属性“forEach”

我花了大约 3 个小时试图了解范围,一个解决方案将是非常有益的。 非常感谢。

【问题讨论】:

  • 你能分享创建挑战的代码吗?你提到了 firebase,所以我想有一些异步操作正在发生?
  • 替代 angular.forEach(scope.challenge, function(challenge) { challenge.visible = false });
  • @Kato 在控制器中我有$scope.findAll = function() { $scope.challenges = Challenge.findAll(); }; 它只是从 Firebase 获取所有结果。
  • @DeadCalimero 我已经尝试过了,但由于 scope.challenges 仍未定义,我也尝试过 $watch 挑战以检查它是否是异步的。
  • @angglada 肯定是一个承诺,Challenge.findAll() 请求一个带有 $http 的 url。你在迭代之前解决了承诺吗?

标签: javascript angularjs angularjs-scope firebase


【解决方案1】:

@rizome 非常感谢您的回答,它真的很有用。

Firebase API 直接返回一个 Promise,因此您不必这样做。

最后我解决了,将 'angularfire' 更新到 v0.8 和这段代码:

// Controller code
Challenge.findAll().$asArray().$loaded().then(function(challenges)
{
    $scope.challenges = challenges;
});

基本上它所做的就是等到准备好分配挑战。

这个来自 firebase 的 article 确实是解决它的好资源。

【讨论】:

  • AngularFire 目前是 0.8.2。在 0.8 和最新版本之间有一些错误修复。
【解决方案2】:

不知道是不是我理解错了,但是:

var currentIndexChangeHandler = function(newValue, oldValue) {
    scope.challenges.forEach(function(challenge) {
        //do something
    }
}
scope.$watch('currentIndex', currentIndexChangeHandler);

将引发“currentIndexChangeHandler”将在第一次运行时触发(参见:$watch is triggered directly after init, why?),此时“scope.challenges”仍未定义。

你用“if(newValue!=oldValue)”来“破解”这个“第一次运行”,但我认为这不是重点。 另一个问题是,当您迭代“scope.challenges”时,它是未定义的,因为它的值应该是异步接收的。可以使用“if(Boolean(scope.challenges))”来解决,但这不是正确的方法。

我认为真正的问题是您正在处理异步数据。

¿什么值返回 Challenge.findAll()? ¿也许是一个承诺?这样你应该使用:

Challenge.findAll().then(function(challenges){
    $scope.challenges = challenges;
}

我根据自己的建议重构了您的代码。是那种行为,你在假装吗?

http://jsfiddle.net/rizome/uqtaoLne/

更新:

使用 Firebase 和 $firebase(请参阅:https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebase

"$firebase" AngularJS 包装器的行为与上面小提琴中的代码类似,但您应该使用 "$firebase" api 来获得承诺。 (这段代码代表你的 repo-service 内部的代码,以及控制器内部的代码)

var firebaseResource = $firebase(new Firebase(YOUR_DATA_URL));
var firebaseSyncArray = firebaseResource.$asArray(); //it is still empty
var loadedArrayPromise = firebaseSyncArray.$loaded(); //promise with the array when loaded
var loadedArrayPromise.then(function (challenges) {
        $scope.challenges = challenges; //now, you can set $scope.challenges
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多