Fetching item by unique firebase id in angularfire 1.0.0

£可爱£侵袭症+ 提交于 2020-01-13 18:19:48

问题


I have trouble fetching one unique item from my firebase using angularfire 1.0.0. To clarify, I want my app to fetch a post given a unique firebase id e.g. "-JkZwz-tyYoRLoRqlI_I". It works when navigating in the app e.g. clicking on a link to a specific post, but not on a refresh. My guess is that it has something to do with synchronization. Right now it works when fetching all posts and use it in a ng-repeat. This is a clue to why it works for one item when navigating to the page. This should probably not be hard since this should be a pretty standard operation, but i can't get it to work. I have searched everywhere but there is actually no guide on this. In the API they refer to $getRecord(key)

Returns the record from the array for the given key. If the key is not found, returns null. This method utilizes $indexFor(key) to find the appropriate record.

But this is not working as expected. Or am i missing something?

It works for ng-repeat like this:

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

But not for unique items like this:

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

This is the service:

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

As the comments say in the get function, the postId is there and posts is also set, but the post is null.

This is the controller

'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

}]);

This is what is an example on what is in the firebase database

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

I find this problem very wierd since it should be very standard. I am obviously missing something, but can't work it out. Any help is very much appreciated!

Thanks in advance!


回答1:


I know that the documentation of the $getRecord() function is kind of misleading. What you actually get from $firebaseArray is a promise of an array. It means that your posts variable will contain your posts at some point in the future. That being said, it seems that the $getRecord function only works when the promise have been resolved, i.e. when the array has been downloaded from Firebase. To make sure that the promise is resolved when you call the $getRecord function, you can use $loaded() on the promise :

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

If you are wondering why it works for ng-repeat, it's because Angular knows that the posts variable is a promise and waits for it to be resolved before rendering the values.




回答2:


This is happening due to promises.

  • Along the lines of what Kato, Jean-Philippe said, $firebaseArray is not immediately available as it needs to be downloaded.
  • See the .$loaded() documentation:

    .$loaded() "returns a promise which is resolved when the initial array data has been downloaded from Firebase. The promise resolves to the $firebaseArray itself."

That answers your question, and I just wanted to show another way of doing it:

  • This is a great use case for extending AngularFire services.
    • As the AngularFire API Documentation says:

      "There are several powerful techniques for transforming the data downloaded and saved by $firebaseArray and $firebaseObject. These techniques should only be attempted by advanced Angular users who know their way around the code."

  • Putting all that together, you accomplish what you want to do by:
    • Extending the Firebase service $firebaseArray
    • Following the documentation for extending services.

Example

  • Here is a working JSFIDDLE example I put together that is tied to one of my public Firebase instances.
  • It's important to note that you should add ".indexOn":"timestamp" to your rules for /posts.

Factories

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

Controller

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


来源:https://stackoverflow.com/questions/29129341/fetching-item-by-unique-firebase-id-in-angularfire-1-0-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!