【问题标题】:Fetching item by unique firebase id in angularfire 1.0.0在angularfire 1.0.0中通过唯一的firebase id获取项目
【发布时间】:2015-05-21 16:00:47
【问题描述】:

我无法使用 angularfire 1.0.0 从我的 Firebase 中获取一件独特的物品。澄清一下,我希望我的应用能够获取给定唯一 Firebase id 的帖子,例如“-JkZwz-tyYoRLoRqlI_I”。它在应用程序中导航时有效,例如单击指向特定帖子的链接,但不单击刷新。我的猜测是它与同步有关。现在它在获取所有帖子并在 ng-repeat 中使用它时工作。这是导航到页面时为什么它适用于一个项目的线索。这可能不难,因为这应该是一个非常标准的操作,但我无法让它工作。我到处搜索,但实际上没有这方面的指南。在 API 中他们引用了$getRecord(key)

从给定键的数组中返回记录。如果没有钥匙 找到,返回null。此方法利用 $indexFor(key) 来查找 适当的记录。

但这并没有按预期工作。还是我错过了什么?

它适用于 ng-repeat,如下所示:

<div ng-repeat="postt in posts">
   <div>
      <h1>{{postt.title}}</h1>
      <div>{{postt.timestamp}}</div>
      <div>{{postt.content}}</div>
   </div>
</div>

但不适用于像这样的独特物品:

<div>
   <h1>{{post.title}}</h1>
   <div>{{post.timestamp}}</div>
   <div>{{post.content}}</div>
</div>

这是服务:

'use strict';

angular.module('app.module.blog.post')

.factory("PostService", ["$firebaseArray", "FIREBASE_URL", function($firebaseArray, FIREBASE_URL) {

    var ref = new Firebase(FIREBASE_URL + "posts");
    var posts = $firebaseArray(ref);

    return {
        all: posts, // ng-repeat on this works fine

        last: function(nr) {
            var query = ref.orderByChild("timestamp").limitToLast(nr);
            return $firebaseArray(query); // ng-repeat on this work fine to
        },
        create: function (post) {
            return posts.$add(post);
        },
        get: function (postId) {
            console.log(postId); // This is -JkZwz-tyYoRLoRqlI_I
            var post = posts.$getRecord(postId);
            console.log(post); // This print null
            return post;
        },
        delete: function (post) {
            return posts.$remove(post);
        }
    };
}]);

正如 cmets 在 get 函数中所说,postId 在那里,posts 也已设置,但 post 为空。

这是控制器

'use strict';

angular.module('app.module.blog.post', [])

.controller('PostCtrl', ['$scope', '$routeParams', 'PostService', function($scope, $routeParams, PostService) {

    // This returns e.g. postId "-JkZwz-tyYoRLoRqlI_I"
    console.log($routeParams.postId);

    $scope.post = PostService.get($routeParams.postId);    
    $scope.posts = PostService.all; // Illustrates the example not actually in this controller otherwise

}]);

这是关于 firebase 数据库中内容的示例

<myfirebase>
 posts
 -JkUnVsGnCqbAxbMailo
 comments
 content: ...
 timestamp: ...
 title: ...
 -JkZwz-tyYoRLoRqlI_I
 comments
 content: ...
 timestamp: ...
 title: ...
 -JkhaEf9tQy06cOF03Ts
 content: ...
 timestamp: ...
 title: ...

我觉得这个问题很奇怪,因为它应该很标准。我显然错过了一些东西,但无法解决。非常感谢任何帮助!

提前致谢!

【问题讨论】:

    标签: arrays angularjs key firebase angularfire


    【解决方案1】:

    我知道$getRecord() 函数的文档有点误导。你实际上从$firebaseArray 得到的是一个数组的promise。这意味着您的 posts 变量将在将来的某个时候包含您的帖子。话虽如此,$getRecord 函数似乎仅在承诺已解决时才有效,即从 Firebase 下载数组时。为了确保在调用 $getRecord 函数时 promise 得到解决,您可以在 promise 上使用 $loaded()

    var posts = $firebaseArray(ref);
    posts.$loaded().then(function(x) {
        var post = x.$getRecord(postId);
        console.log(post);
    }).catch(function(error) {
        console.log("Error:", error);
    });
    

    如果您想知道为什么它适用于 ng-repeat,那是因为 Angular 知道 posts 变量是一个承诺,并在呈现值之前等待它被解析。

    【讨论】:

    • 在将 $loaded() 放入我的控制器然后分配 $scope.post 后,这解决了我的主要问题。非常感谢!
    • 很高兴听到这些文档是如何误导的,以及为什么人们期望必须从远程服务器加载的数据会立即出现。请随时与我们联系以提供反馈。
    • $getRecord,firebase.com/docs/web/libraries/angular/…下的API中有说明:var list = $firebaseArray(ref); var rec = list.$getRecord("foo"); // record with $id === "foo" or null这表示$getRecord("foo")可以在列表创建后直接调用。这不起作用,在我看来这有点误导。参考$loaded 文档会很好。
    • 嗨 Kato,我应该说“$getRecord() 函数文档”而不是 firebase 文档。就像 Mattias 说的,我认为 $getRecord() 函数文档/示例对于那些不是真正喜欢 Angularjs 的人来说可能有点误导......我会将我的反馈发送给支持团队!
    【解决方案2】:

    这是由于承诺而发生的。

    • 正如加藤所言,Jean-Philippe 所说,$firebaseArray 无法立即使用,因为需要下载。
    • 请参阅.$loaded() 文档:

      .$loaded() "返回一个承诺,当从 Firebase 下载初始数组数据时,该承诺将被解析。该承诺将解析为 $firebaseArray 本身。"

    这回答了你的问题,我只是想展示另一种方法:

    • 这是扩展 AngularFire 服务的一个很好的用例。
      • 正如AngularFire API Documentation 所说:

        “有几种强大的技术可以转换$firebaseArray$firebaseObject 下载和保存的数据。这些技术只能由熟悉代码的高级Angular 用户尝试。”

    • 将所有这些放在一起,您可以通过以下方式完成您想做的事情:

    示例

    • 这是我整理的一个有效的JSFIDDLE example,它与我的一个公共 Firebase 实例相关联。
    • 请务必注意,您应将".indexOn":"timestamp" 添加到/posts 的规则中。

    工厂

    app.factory('PostsArray', function (FBURL, PostsArrayFactory) {
        return function (limitToLast) {
            if (!limitToLast) {
                console.error("Need limitToLast");
                return null;
            }
            var postsRef = new Firebase(FBURL + '/posts').orderByChild('timestamp').limitToLast(limitToLast);
            return new PostsArrayFactory(postsRef);
        }
    });
    
    
    app.factory('PostsArrayFactory', function ($q, $firebaseArray) {
        return $firebaseArray.$extend({
            getPost: function (postKey) {
                var deferred = $q.defer();
                var post = this.$getRecord(postKey);
                if (post) {
                    console.log("Got post", post);
                    deferred.resolve(post);
                } else {
                    deferred.reject("Post with key:" + postKey + " not found.");
                }
                return deferred.promise;
            },
            createPost: function (post) {
                var deferred = $q.defer();
                post.timestamp = Firebase.ServerValue.TIMESTAMP;
                this.$add(post).then(function (ref) {
                    var id = ref.key();
                    console.log("added post with id", id, "post:", post);
                    deferred.resolve(ref);
                }).
                catch (function (error) {
                    deferred.reject(error);
                });
                return deferred.promise;
            }
        });
    });
    

    控制器

    app.controller("SampleController", function ($scope, PostsArray) {
    
        var posts = new PostsArray(5);
        $scope.posts = posts;
    
        $scope.newPost = {};
        $scope.createNewPost = function () {
            posts.createPost($scope.newPost);
        }
    
        $scope.postId = '';
        $scope.getPost = function () {
            posts.getPost($scope.postId).then(function (post) {
                $scope.gotPost = post;
            }).
            catch (function (error) {
                $scope.gotPost = error;
            });
        }
    });
    

    【讨论】:

    • 非常好的输入!我现在扩展了 $firebaseArray。但是,上面的示例仅适用于按钮单击,而不适用于刷新调用。我在 promise 上使用了 $loaded 函数,现在它可以正常工作了。
    • 是的!这只是一个示例,不一定直接应用您的问题,因为 Jean-Philippe 已经为您的用例提供了答案。您还可以将$loaded() 放在控制器中,然后在单击按钮时运行获取和创建功能not
    猜你喜欢
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多