0

I am using AngularJS to set up a table and filter its data by a search or category keywords. I

AngularJS

categorieFilter = angular.module("categorieFilter", [])
categorieFilter.controller("catFilter", ["$scope", "store", function($scope, store){
    $scope.search = "";
    $scope.products = [];
    $scope.categories = [];

    $scope.categories = store.getCategories();
    $scope.products = store.getProducts();

    $scope.filterProductsByCats = function(category){
    $scope.search = category;
    };
}])
categorieFilter.factory('store', function($http){
          return {
            getCategories: $http.get('api/categories').success(function (data) {
                return data;
            }),
            getProducts : $http.get('api/products').success(function (data) {
                return data;
            }
        };
    });  

The $http.get on its own is working, when I surf directly to my api I get the required data. Also when I do a alert(data) ifter the $hhtp.get in categories, I get the data I need... So this should be working but it doesn't. I get an error:

TypeError: store.getCategories is not a function

And I got no clue where this is coming from. Anybody a solution to this problem?

Sesamzaad
  • 462
  • 8
  • 25

4 Answers4

1

When using a factory you should do new function to return a constructor:

function myFactoryFunction() {
    return function() {
        var a = 2;
        this.a2 = function() {
            return a*2;
        };
    };
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();

From this detailed post angular.service vs angular.factory

In your case

var storeFactory = new store();
storeFactory.getProducts();

Updated version, with TS code:

categorieFilter = angular.module("categorieFilter", [])
/**
Store factory
*/
categorieFilter.controller("catFilter", ["$scope", "store", function($scope, store){
    $scope.search = "";
    $scope.products = [];
    $scope.categories = [];

    store.getCategories().then(function(data){
        $scope.categories = data;
    })

    store.getProducts().then(function(data){
        $scope.products = data;
    })

    $scope.filterProductsByCats = function(category){
    $scope.search = category;
    };
}])



/**
Store factory
*/
categorieFilter.factory('store', function($http, $q){

    function _getCategory (){
        var deferred = $q.defer();

        $http.get('api/categories').success(function (data) {
                deferred.resolve(data);
            })

        return deferred.promise;
    }

    function _getProducts (){
        var deferred = $q.defer();

        $http.get('api/products').success(function (data) {
                        deferred.resolve(data);
                    }

        return deferred.promise;
    }


          return {
            getCategories: _getCategory,
            getProducts : _getProducts
        };
    });  
Community
  • 1
  • 1
shershen
  • 9,875
  • 11
  • 39
  • 60
  • Could you edit it in my code? Cause when I do what I think your saying I get another error: TypeError: object is not a function – Sesamzaad May 11 '15 at 08:20
  • I get the data from my server but I get each item as: ["Lattes"],["CC Blend"],...? When I just alert the data it looks normal. Has this something to do with the deffered? – Sesamzaad May 11 '15 at 09:02
  • deffered is just a way to implement Promise, async way AJAX works; so if you getting the right data then you should be able to access it, like $scope.products = data[0]; – shershen May 11 '15 at 09:22
  • Yes sorry found it right after my own comment. This works great thanks a lot for helping! – Sesamzaad May 11 '15 at 09:30
0

I usually create services using $resource. You could try this:

categorieFilter = angular.module("categorieFilter", []);

categorieFilter.factory('categoryStore', [
  '$resource',
  function($resource) {
    return $resource('/api/categories/', {}, {
      getCategories: { method: 'GET', params: {} },
    });
  }
]);

categorieFilter.factory('productsStore', [
  '$resource',
  function ($resource) {
    return $resource('/api/products/', {}, {
      getProducts: { method: 'GET', params: {} },
    });
  }
]);

categorieFilter.controller("catFilter", [
  "$scope", "categoryStore", "productsStore", function ($scope, categoryStore, productsStore) {
    $scope.search = "";
    $scope.products = [];
    $scope.categories = [];

    $scope.categories = categoryStore.getCategories();
    $scope.products = productsStore.getProducts();
    $scope.filterProductsByCats = function(category) {
      $scope.search = category;
    };
  }
]);
Clark Kent
  • 305
  • 1
  • 4
  • 16
  • It doesn't recognize $resource I guess? Error: [$injector:unpr] Unknown provider: $resourceProvider <- $resource <- categoryStore – Sesamzaad May 11 '15 at 08:25
  • add 'ngResource', as a depenancy as such: angular.module('helpdesk', [ 'ngResource', 'ui.bootstrap', 'helpdeskServices', 'helpdeskControllers', 'ngMaterial', 'autoCompleteControllers', 'menu' ]); – Clark Kent May 11 '15 at 08:32
0

I usually write http factories passing a callback function parameter (I usually work with Node and I'm used to do this for long working functions). Taking your code it will looks something like this:

categorieFilter = angular.module("categorieFilter", [])
categorieFilter.controller("catFilter", ["$scope", "store", function($scope, store){
    $scope.search = "";
    $scope.products = [];
    $scope.categories = [];

    store.getCategories(function(err, data){
      if(!err)
        $scope.categories = data;
    });
    store.getProducts(function(err, data){
      if(!err)
        $scope.products = data;
    });

    $scope.filterProductsByCats = function(category){
    $scope.search = category;
    };
}])
categorieFilter.factory('store', function($http){
          return {
            getCategories: function(next){
              $http.get('api/categories')
              .success(function (data) {
                next(null, data);
              })
              .error(function(headers, status){
                next(status, null);
              });
            },
            getProducts : function(next){
             $http.get('api/products')              
             .success(function (data) {
                next(null, data);
              })
              .error(function(headers, status){
                next(status, null);
              });

            }
        };
    });  

As you can see now factory takes a callback that will be called with error and data parameters, so error handling can be delegate or not to the controller. This is pretty useful for complex situations.

vktr
  • 149
  • 9
0

Here's a plunker that works using $q and defer explicitly with some random JSON.

var app = angular.module('categorieFilter', []);

app.factory('store', function($http, $q){

  return {
    getCategories: function() {
      var deferred = $q.defer();
        $http.get('https://api.myjson.com/bins/2gamd')
          .success(deferred.resolve)
          .error(deferred.resolve);
        return deferred.promise;
    }
  }

})

.controller('catFilter', function($scope, store){

    store.getCategories().then(function(data) {
      $scope.categories = data.stories;// change data.stories to whatever your data is
    });

});
chris
  • 1,787
  • 1
  • 13
  • 13