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.
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;
}]);