Search code examples
angularjsangularjs-serviceangularjs-factory

Proper way to structure my controller, service, and factory in angularjs application...service or factory?


I have been working with wrapping my head around the "angularjs" way of thinking (Angular 1) and I have a relatively ok grasp as I work my way through a small personal project. I am at a bit of a roadblock, not because I cannot get it to work, but I would like to know what the proper way to set up the data in my application.

The basic situation is this:

I have 3 json files:

categories.json
products.json
vendors.json

These hold the data (which I will fetch from a database later but am simplifying for now).

I basically need to load the data from all three of these files so that I can form a variable holding all "Products" (which is a JS class I declared separately).

I started off by storing the data inside one controller (relevant code below):

myApp.controller('productListController', ['$scope', '$http', '$q', function ($scope, $http, $q) {

var promises = [];
promises.push(getCategories($http));
promises.push(getVendors($http));
promises.push(getProducts($http));

$q.all(promises).then(function (response) {
  //categories = response[0];
  //vendors = response[1];
  //products = response[2];
  $scope.products = createProductList(response);
  $scope.vendors = response[1].data;
  $scope.vendorChecked = getCheckedVendors($scope.vendors);
})

This worked fine but I realized that I need this data in other views, which led me to try to move this code into a service.

The problem I had when doing this is that I do not know of a way for the controller to know that the service is done fetching the data so that I can then save it in the ProductListController $scope.

I would need to have a way to for example:

myApp.service('ProductService', ['$http', '$q', function ($http, $q) {

self = this;
var promises = [];
promises.push(getCategories($http));
promises.push(getVendors($http));
promises.push(getProducts($http));

$q.all(promises).then(function (response) {
//These three I would like to update in ProductListController
//when it is done.
  self.products = createProductList(response);
  self.vendors = response[1].data;
  self.vendorChecked = getCheckedVendors(self.vendors);
})

Is this the correct approach to take? If so, how can I let the controller know that the service is done fetching the data and save for example:

$scope.products = ProductService.products;
$scope.vendors = ProductService.vendors;
$scope.categories = ProductService.categories;

Is this even the correct approach? Another approach I thought of was to use a factory instead of a service. Then I had another problem because I had for example:

return {
    getProducts: function() {
         //http get request code in here
         return promise
    },
    getVendors: function() {
         //http get request code in here
        return promise
    },
    getCategories: function() {
         //http get request code in here
        return promise
    },
    getAllData: function () {
    //in here I want to use the three promises in the 3 functions above
    //but I am not able to call them from here. If I was able to do that
    //then I could call this method from ProductListController and get the
    //data that way.
    }

I am sorry if this is long but I wanted to describe the different things I tried. I know I can make it work but I want to learn the right way, or a couple of right ways.


Solution

  • It is better to always return promise:

    var promises = [];
    promises.push(getCategories($http));
    promises.push(getVendors($http));
    promises.push(getProducts($http));
    
    return $q.all(promises)
    

    If you also not satisfied that in each controller you should call createProductList,getCheckedVendors - consider putting this tranforms to $http transformResponce https://docs.angularjs.org/api/ng/service/$http. Or you can create your own promise. (Using $q.defer https://docs.angularjs.org/api/ng/service/$q).

    Using servie or factory actually doesnt matter. This is factory:

    var factory = {};
    factory.getProducts: function() {
             return promise
    }
    factory.getCategories: function() {
             return promise
    }
    factory.getVendors: function() {
             return promise
    }
    factory.getAllData: function () {
        var promises = [];
        promises.push(factory.getProducts());
        promises.push(factory.getCategories());
        promises.push(factory.getVendors());
    
        return $q.all(promises)
    }
    return factory;
    

    And in controler you just have: MyFactory.getAllData().then(...)