user3527354
user3527354

Reputation: 586

Firebase binding not being reflected in Angular view

I am pulling out one value from every object in Firebase, picUrl (the url of a picture) and storing that in a scope array variable, $scope.bricks. How do I make it so $scope.bricks updates everytime Firebase is updated with a new object, and therefore new picUrl? Thanks in advance!

angular.module('noorApp').controller('MainCtrl', function ($scope, $http, $firebase) {
    var sync = $firebase(ref);
    var firebaseObj = sync.$asObject();
    $scope.bricks = [];

    firebaseObj.$loaded().then(function(){
        angular.forEach(firebaseObj.products, function(value, key){
            $scope.bricks.push({src: value.picUrl});
        });
    });
});

EDIT:

I should have posted how I'm using $scope.bricks in the DOM.

<div class="masonry-brick" ng-repeat="brick in bricks">
  <img ng-src="{{ brick.src }}">
</div>

The issue is that while firebaseObj is synced with Firebase, $loaded() is only running once.
Thanks.

Upvotes: 3

Views: 1361

Answers (2)

user3527354
user3527354

Reputation: 586

After reading Frank's answer, I realized my problem was with my html. I was trying to create a new variable from my synced variable when I didn't need to. I can just reference the synced variable directly.

I should have modified my ng-repeat variable rather than my model. firebaseObj is synced with Firebase, so lets put that on the $scope.

angular.module('noorApp').controller('MainCtrl', function ($scope, $http, $firebase) {
    var sync = $firebase(ref);
    $scope.firebaseObj = sync.$asObject();
});

Now in the DOM, I should just reference firebaseObj:

<div class="masonry-brick" ng-repeat="brick in firebaseObj.products">
   <img ng-src="{{ brick.picUrl }}">
</div>

Or as Frank said, we can just pull the products document from Firebase:

angular.module('noorApp').controller('MainCtrl', function ($scope, $http, $firebase) {
    $scope.bricks = $firebase(ref).products.$asArray();
});

In this case, the html would look like this:

<div class="masonry-brick" ng-repeat="brick in bricks">
  <img ng-src="{{ brick.picUrl }}">
</div>

The point is that by referencing synced variable directly, I don't need $loaded() to run!

Thanks Frank.

Upvotes: 2

Frank van Puffelen
Frank van Puffelen

Reputation: 599061

As I said in my comment, you can probably get it working by:

    firebaseObj.$loaded().then(function(){
        angular.forEach(firebaseObj.products, function(value, key){
            $scope.bricks.push({src: value.picUrl});
            $scopy.$apply();
        });
    });

Update: the above doesn't work, see OP's comment below.

To learn more about $scope.$apply read this article: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

But even though this may fix your current issue, you'll run into other problems later. The reason for this is that you're creating an "unmanaged array" of bricks. AngularFire has quite some code to ensure that Firebase's order collections and AngularJS's two-way data-bound arrays play nice together.

For this reason it is probably better if you set up a separate sync for your array of products:

angular.module('noorApp').controller('MainCtrl', function ($scope, $http, $firebase) {
    var sync = $firebase(ref);
    var firebaseObj = sync.$asObject();
    $scope.bricks = $firebase(ref.child('products')).$asArray();    
});

With this setup, AngularFire will call $apply() automaticaly when the array items initially load or are modified afterwards.

Upvotes: 4

Related Questions