MonkRocker
MonkRocker

Reputation: 309

is this just a bad use-case for AngularFire?

I have been playing around with AngularFire for a few days now, and I'm wondering if I might just be trying what is ultimately a bad use-case for it. I will be doing real-time chat/presence on my site, so that part is useful. This piece I'm working on, though - I dunno.

So I have a registration form. When users register they have to choose a color from a drop down list. I have the list stored in an array in Firebase.

I am trying to maintain a fairly strict MVC setup, so I have each controller in its own file, as well as each corresponding service. Previous angular apps I have written used the structure and it has worked well, until now.

What I can't figure out is the correct way to simply read back the list and populate it into the dropdown.

In previous angular apps, it was just straight up something like:

return $resource(URL + /colors);

So in AngularFire, I was using basically this, which is working, buuuuutttt:

getColors: function($scope) {
            syncData('usergen/colors').$bind($scope, 'colorsRaw').then(function() {
                var keys = $scope.colorsRaw.$getIndex();
                angular.forEach(keys, function(key) {
                    var color = {label: $scope.colorsRaw[key], value: $scope.colorsRaw[key]};
                    $scope.data.colors.push(color);
                });
                $scope.data.color = $scope.data.colors[Math.floor(Math.random() * $scope.data.colors.length)];
            });
        }

Now of course what I absolutely HATE about it: why am I having to pass $scope around like that? I can't seem to just have getColor() return a regular array of {name: "Blue", value: "Blue"} objects. Not only do I have to pass $scope around, I can't set the drop down to a random value unless I do it in the service. Bad bad bad. I don't want to pass the Ctrl $scope into the service at all and I certainly don't want to be updating Ctrl $scope variables from the service.

So what on earth am I missing here? Firebase seems pretty well developed, so I'm sure it's my complete lack of understanding. I worked through all the chat examples and tutorials and things, but there's nothing quite like what I'm trying to do here.

So is there a way to have a separate service for Firebase/AngularFire calls which allows me to just return values to my Controller without having to pass in a $scope var?

Thanks.

Upvotes: 4

Views: 418

Answers (1)

David East
David East

Reputation: 32604

Now of course what I absolutely HATE about it: why am I having to pass $scope around like that?

A lot people think you have to use $scope with AngularFire. Not only can you use it without $scope, it's recommended in most cases.

Using AngularFire in $scope too much can really slow down your app as well because Angular is now tasked with keeping track of it.

When working AngularFire I usually create my $firebase bindings on a factory/service level. This way it becomes reusable and easy to maintain. Then I can create simple arrays on my controller's $scope and push when new items are added.

Plunker Demo

angular.module('app', ['firebase'])

.constant('FBURL', 'https://<your-firebase>.firebaseio.com/')

.service('FbRef', ['FBURL', Firebase])

.factory('Colors', function (FbRef, $firebase, $q) {
    var $colors = $firebase(FbRef.child('colors'));
    return {
        get: function getColors() {
            var deferred = $q.defer();

            $colors.$on('loaded', function (colors) {

                var colorArr = [];
                angular.forEach(colors, function (color) {
                    colorArr.push(color);
                });

                deferred.resolve(colorArr);
            });

            return deferred.promise;
        },
        add: function addColor(color) {
            $colors.$add(color);
        }
    };
})

.controller('RegisterCtrl', function ($scope, Colors) {

    $scope.colors = [];

    // listen for added colors
    // this will grab all of the colors on load
    Colors.get().then(function (colors) {
        $scope.colors = colors;
        var randomIndex = getRandomIndex(0, colors.length - 1);
        $scope.current = colors[randomIndex];
    });

    function getRandomIndex(min, max) {
        return Math.floor(Math.random() * max) + min;
    }

});

The View is just a simple select with ng-model and ng-options.

<select ng-model="current" ng-options="c for c in colors"></select>

Upvotes: 1

Related Questions