Joining AngularFire paths on a value/key is not working (merging user profiles into records)

前端 未结 3 1145
长发绾君心
长发绾君心 2021-01-25 02:10

I am developing an application with Firebase (1.0) and Angular (1.4). The problem I\'m having is to ensure the data in view are synchronised with Firebase, while fetching denorm

3条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-01-25 03:04

    Brandon's answer is technically-correct answer to the posed question. I'm going to elaborate a bit on what would be a better way to join these records.

    I've actually answered this exact question in a fiddle, and also provided a more sophisticated, elegant, and simpler solution of how to cache and merge user profiles into objects. I'll reiterate the details of how this works here.

    app.factory('NormalizedPosts', function($firebaseArray, userCache) {
      var PostsWithUsers = $firebaseArray.$extend({
    
       // override $$added to include users
       $$added: function(snap) {
           // call the super method
           var record = $firebaseArray.prototype.$$added.call(this, snap);
           userCache.$load( record.user ).$loaded(function( userData ) {
                record.userData = userData;
           });
           // return the modified record
           return record;
       }
    
      });
      return PostsWithUsers;
    });
    

    Here I've decided to use a cached list of users, since they are likely to be highly redundant, and this provides an elegant way to keep everything in sync. It's not strictly necessary--we could look them up right there in $$added, but that leaves some edge cases to be handled. So a cache of synchronized users feels right here.

    So here's the caching utility:

    app.factory('userCache', function ($firebase) {
        return function (ref) {
            var cachedUsers = {};
            // loads one user into the local cache, you do not need to
            // wait for this to show it in your view, Angular and Firebase
            // will work out the details in the background
            cachedUsers.$load = function (id) {
                if( !cachedUsers.hasOwnProperty(id) ) {
                    cachedUsers[id] = $firebaseObject(ref.child(id));
                }
                return cachedUsers[id];
            };
            // frees memory and stops listening on user objects
            // use this when you switch views in your SPA and no longer
            // need this list
            cachedUsers.$dispose = function () {
                angular.forEach(cachedUsers, function (user) {
                    user.$destroy();
                });
            };
            // removes one user, note that the user does not have
            // to be cached locally for this to work
            cachedUsers.$remove = function(id) {
                delete cachedUsers[id];
                ref.child(id).remove();
            };
            return cachedUsers;
        }
    });
    

    And here's a gist putting it all together.

    Note that, if we know that when our controller is destroyed, that the data will no longer be useful, we can clean up the listeners and memory by calling $destroy. This isn't strictly necessary and could be a premature optimization, but is probably worth mentioning for users with complex production apps that have tens of thousands of records to track:

    app.controller('...', function(NormalizedPosts, userCache, $scope) {
       $scope.posts = new NormalizedPosts();
       $scope.$on('$destroy', function() {
          $scope.posts.$destroy();
          userCache.$dispose();
       });
    });
    

提交回复
热议问题