1
votes

I've got a factory that gets my data from Firebase, and I want my controller to be able to access it. However, when I console.log the data in my controller, it isn't the Array[10] that I would expect it to be, but rather an Array with keys 0,1,2,..10, $$added, $$error, $$moved,... and so on. However, when I skip out on using the factory, and use $asArray() method on my firebase ref directly in my controller it shows up nicely as an Array[10]

In my factory, this is what it looks like..

var listingsref = new Firebase("https://something.firebaseio.com");
var sync2 = $firebase(listingsref);
var products = sync2.$asArray();
factory.getProducts = function(){
    return products;
};

Controller

$scope.products = marketFactory.getProducts();

console.log($scope.products) in my controller should be Array[10], but instead it's an Array with the data + a lot more $$ methods. Anyone know what's going on? Thanks

EDIT: Full Factory File

(function(){
var marketFactory = function($firebase){
    var listingsref = new Firebase("https://something.firebaseio.com");
    var sync2 = $firebase(listingsref);
    var products = sync2.$asArray();

    var factory = {};
    factory.getProducts = function(){
        console.log(products);
        return products;
    };

    factory.getProduct = function(productId){
        for(var x = 0; x<products.length ;x++){
            if(productId == products[x].id){
                return {
                    product:products[x],
                    dataPlace:x
                };
            }
        }
        return {};
    };

    factory.getNextProduct = function(productId, e){
        var currentProductPlace = factory.getProduct(productId).dataPlace;
        if (e=="next" && currentProductPlace<products.length){
            return products[currentProductPlace+1];
        }

        else if(e=="prev" && currentProductPlace>0){
            return products[currentProductPlace-1];
        }
        else{
            return {};
        }
    };

    factory.componentToHex = function(c){
        var hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    };

    factory.rgbToHex = function(r,g,b){
        return "#" + factory.componentToHex(r) + factory.componentToHex(g) + factory.componentToHex(b);
    };

    factory.hexToRgb = function(hex) {
        if(hex.charAt(0)==="#"){
            hex = hex.substr(1);
        }
        var bigint = parseInt(hex, 16);
        var r = (bigint >> 16) & 255;
        var g = (bigint >> 8) & 255;
        var b = bigint & 255;

        return r + ", " + g + ", " + b;
    };

    factory.parseRgb = function(rgb){
        rgb = rgb.replace(/\s/g, '');
        var red = parseInt(rgb.split(',')[0]);
        var green = parseInt(rgb.split(',')[1]);
        var blue = parseInt(rgb.split(',')[2]);

        return {
            r:red,
            g:green,
            b:blue
        };
    };

    return factory;
};

marketFactory.$inject = ['$firebase'];
angular.module('marketApp').factory('marketFactory', marketFactory);
}());
2
Can you list the code for the full factory? I think I know what the problem is but I need to confirm. - rtucker88
Sure, I just edited the post. - pyramidface
Pretty much everything here is incorrect. Please have a look at the guide and try to use the lib as designed. For example, there is already a method to get items by id, the id should be $id, the factory methods you've created should be added using $extendFactory, and debugging should be done with something like {{products|json}} in the view, or $loaded(console.log) in the service. A little documentation goes a long way. - Kato

2 Answers

7
votes

This snippet gets a synchronized AngulareFire array of products:

var products = sync2.$asArray();

The AngularFire documentation is a bit off on this point: what you get back from $asArray() is not an array, but the promise of an array. At some point in the future your products variable will contain an array. This is done because it may take (quite) some time for your array data to be downloaded from Firebase. Instead of blocking your code/browser while the data is downloading, it returns a wrapper object (called a promise) and just continues.

Such a promise is good enough for AngularJS: if you simply bind products to the scope and ng-repeat over it, your view will show all products just fine. This is because AngularFire behind the scenes lets AngularJS know when the data is available and Angular then redraws the view.

But you said:

console.log($scope.products) in my controller should be Array[10]

That is where you're mistaken. While AngularFire ensures that its $asArray() promise works fine with AngularJS, it doesn't do the same for console.log. So your console.log code runs before the data has been downloaded from Firebase.

If you really must log the products, you should wait until the promise is resolved. You this this with the following construct:

products.$loaded().then(function(products) {
    console.log(products);
});

When you code it like this snippet, the data for your products will have been downloaded by the time console.log runs.

Note that the object will still have extra helper methods on it, such as $add. That is normal and also valid on an array. See the documentation for FirebaseArray for more information on what the methods are, what they're for an how to use them.

0
votes

So I edited the code in the plnkr at http://plnkr.co/M4PqojtgRhDqU475NoRY.

The main differences are the following:

// Add $FirebaseArray so we can extend the factory
var marketFactory = function($firebase, $FirebaseArray){
var listingsref = new Firebase("https://something.firebaseio.com");

// Actually extend the AngularFire factory and return the array
var MarketFactory = $FirebaseArray.$extendFactory(factory);
return function() {
  var sync = $firebase(listingsref, {arrayFactory: factory});

  return sync.$asArray();
};

Check out https://www.firebase.com/docs/web/libraries/angular/guide.html#section-extending-factories for more information on extending AngularFire entries. You will likely need to make some adjustments to the rest of the factory code.