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?

4 Answers 4

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
        };
    });  
Sign up to request clarification or add additional context in comments.

4 Comments

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
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?
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];
Yes sorry found it right after my own comment. This works great thanks a lot for helping!
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;
    };
  }
]);

2 Comments

It doesn't recognize $resource I guess? Error: [$injector:unpr] Unknown provider: $resourceProvider <- $resource <- categoryStore
add 'ngResource', as a depenancy as such: angular.module('helpdesk', [ 'ngResource', 'ui.bootstrap', 'helpdeskServices', 'helpdeskControllers', 'ngMaterial', 'autoCompleteControllers', 'menu' ]);
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.

Comments

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

});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.