javascriptangularjsparse-platformangularjs-factory

Get data from Parse.com using AngularJS factory


I'm developing an e-commerce web app using AngularJS (v1.6.7) and Parse Server (v2.3.3).

I created Category and Product class in Parse Server. I'm trying to fetch in a certain amount of products per category.

For example, in homepage, 20 products will be retrieved per category. The amount of products changes in other pages.

I want to do it using a factory that fetches given amount of products in any category (amount and category of products will be passed to the function as parameters). So I'll be able to reuse it inside other controllers.

ProductsFactory factory:

sebetimapp.factory('ProductsFactory', ['$q', function($q){
    Parse.initialize('MY_APP_ID', 'JS_KEY');
    Parse.serverURL = 'https://parseapi.back4app.com/';

    let fac = {};

    fac.getProducts = function(cat, lmt) {
        let Category = Parse.Object.extend('Category'),
            qr = new Parse.Query(Category);

        qr.get(cat, {
            success: function (res) {
                let product_dfd = $q.defer(),
                    Product = Parse.Object.extend('Product'),
                    query = new Parse.Query(Product);

                query.include('category');

                query.equalTo('category', res);

                if (lmt) {
                    query.limit(lmt);
                }

                query.find({
                    success: function(results) {
                        product_dfd.resolve(results);
                    },
                    error: function(err) {
                        product_dfd.reject(results);
                    }
                });

                return product_dfd.promise;
            },
            error: function(object, error) {
                //
            }
        });
    };

    return fac;
}]);

productsCtrl controller:

sebetimapp.controller('productsCtrl', ['$scope', '$log', '$location', '$q', 'ProductsFactory', function($scope, $log, $location, $q, ProductsFactory) {
    let params = $location.search(); // To grab category ID from URL.

    ProductsFactory.getProducts(params.cat, 20).then(function(response) {
        $log.log('Successfully retrieved products.');
    }, function(error) {
        $log.log('Unable to get products.');
    });
}]);

When I execute it, an error occurs:

TypeError: Cannot read property 'then' of undefined

But if I don't use this factory and define getProducts() function inside my controller, it works fine.

Why is this happening? I'm new to AngularJS. Any help would be appreciated.


Solution

  • The .then() method is only available on Promises. Your function appears to be not returning anything (and hence, .then() is unavailable).

    This might help:

    sebetimapp.factory('ProductsFactory', ['$q', function($q) {
      Parse.initialize('MY_APP_ID', 'JS_KEY');
      Parse.serverURL = 'https://parseapi.back4app.com/';
      var fac = {};
      fac.getProducts = function(cat, lmt) {
        var Category = Parse.Object.extend('Category'),
          qr = new Parse.Query(Category);
        return qr.get(cat)
          .then(function(res) {
            var Product = Parse.Object.extend('Product'),
              query = new Parse.Query(Product);
            query.include('category');
            query.equalTo('category', res);
            if (lmt) {
              query.limit(lmt);
            }
            return query.find();
          });
      };
      return fac;
    }]);

    Most methods in the Parse JS API return promises. You can use those directly (and not use the success and error callbacks). It's been ages since I worked on Parse (I thought it was no longer available) so you may have to figure out the details yourself.. Handy Link: http://docs.parseplatform.org/js/guide/#promises

    TLDR; Your factory function needs to return a promise but is returning nothing and hence .then() is unavilable

    EDIT: Here is another way to the same thing with minimal changes to you original code (this is not the best way to do this, however)

    sebetimapp.factory('ProductsFactory', ['$q', function($q) {
      Parse.initialize('MY_APP_ID', 'JS_KEY');
      Parse.serverURL = 'https://parseapi.back4app.com/';
      var fac = {};
      fac.getProducts = function(cat, lmt) {
        var Category = Parse.Object.extend('Category'),
          qr = new Parse.Query(Category),
          // Move the deffered object out of the inner function
          product_dfd = $q.defer();
        qr.get(cat, {
          success: function(res) {
            var Product = Parse.Object.extend('Product'),
              query = new Parse.Query(Product);
            query.include('category');
            query.equalTo('category', res);
            if (lmt) {
              query.limit(lmt);
            }
            query.find({
              success: function(results) {
                product_dfd.resolve(results);
              },
              error: function(err) {
                product_dfd.reject(results);
              }
            });
          },
          error: function(object, error) {}
        });
        // Return the deferred object
        return product_dfd.promise;
      };
      return fac;
    }]);