Angular.js & Parse - wrapping Parse API calls up in a tidy service

Spending a bit of time with Angular.js & Parse, there’s some rough edges to smooth out. I’m not quite there yet, but finally have a factory working a way I’m mostly happy with.

1. Getting ready to use Parse

Add Parse from CDN. Later (when it all works!) you’ll want to bring this into your codebase.

`<script src="//www.parsecdn.com/js/parse-1.6.14.min.js"></script>`

I’m working with Ionic, so under $ionicPlatform.ready, place the Parse init code.

`Parse.initialize("(APP ID)", "(JS KEY)");`
2. Set up a factory for each class you want from Parse.

Parse is now in your global scope and has been initialised. Create a services.js file if you don’t have one already and reference it in index.html. This is where we will store the factory for each class.

Boilerplate for your services file
  angular.module('APP_NAME.services', [])

For each class required from Parse, you need a factory to return the records. This modularization (in theory) allows you to swap out Parse in the future and creates cleaner code by hiding away the Parse cruft from your controllers (keep reading).

Factory for the 'Order' class in Parse - exposes query() and get($id)
    .factory('ParseProductService', function($q){
        var query = new Parse.Query(Parse.Object.extend("Product"));
        return {
            query: function(){
                var defer = $q.defer();
                query.find({
                    success: function(results){
                        defer.resolve(results);
                    },
                    error: function(error){
                        defer.reject(error);
                    }
                });
                return defer.promise;
            },
            get: function(id){
                var defer = $q.defer();
                query.get(id,{
                    success: function(result){
                        defer.resolve(result);
                    },
                    error: function(error){
                        defer.reject(error);
                    }
                });
                return defer.promise;
            }
        }

Now, we can consume the factory in a controller. In my project, I visit my relevant controller and check I have listed the factory name as a dependency, ParseProductService.

.controller('ProductCtrl', function($scope, $stateParams, LocalStorageService, ParseProductService) {.

My controller can now call the query and get methods through ParseProductService, and when the promise is returned, act on the results.

Getting a product (by ID) from the Product Service (Factory) and storing the resulting product in $scope.product
ParseProductService.get({product: productId}).then(function(p){
  $scope.product = p;
});
Asking Parse for all products this user can access - and storing the resulting array in $scope.products
ParseProductService.query().then(function(p){
  $scope.products = p;
})

Next up, working around the damned setters/getters from Parse API! {{product.get('name')}}.