1

I have 2 controllers (Products) and (ProductsFilters) and 1 service (ProductService).

The 2 controllers are being loaded at the same time as the 2nd one (ProductsFilter) acts as a side menu for the first controller (Products).

Products controller calls AJAX service through ProductService and assign the returned data to a variable(Facets) in ProductService.

At same time the the ProductsFilter retrieve the (Facets) from ProductService.

The problem now, that I want to process some data in ProductsFilter controller before it is getting displayed in the view, but at the time of execution, the ProductService.Facets return an empty object because the AJAX call has not been finished yet!

I tried to $watch() the ProductService.Facets but it didn't work.

Here is the product service

.factory('ProductService', function(AppService, CategoryService, $stateParams, $location, $http) {
return {
facets: {},
browse: function(category_id, page, order, order_type) {

  url = AppService.apiUrl() + 'products/browse.json?' + params;

  var that = this;

  return this.getProducts(url).then(function(response) {
    that.facets.grouped_brands = response.grouped_brands;
    that.facets.grouped_categories = response.grouped_categories;
    that.facets.grouped_prices = response.grouped_prices;
    that.facets.grouped_stores = response.grouped_stores;

    return response;
  });

},
getProducts: function(url) {
  return $http.jsonp(url + '&callback=JSON_CALLBACK&ref=mobile_app', {cache: true})
    .then(function(response) {
      if (typeof response.data === 'object') {
        return response.data;
      }
    });
   }
  }
 })

Here is the Products controller:

.controller('ProductsController', function($scope, ProductService) {

  $scope.page = 1;

  $scope.moreProducts = function() {
    ProductService.browse(180, $scope.page)
      .then(function(products) {
        angular.extend($scope.products, products.products);
        $scope.page +=1;
      }
    );
  }

  $scope.products = {}

})

And here is the ProductsFilter controller:

.controller('ProductsFiltersController', function($scope, ProductService) {
  $scope.facets = ProductService.facets;
  $scope.brand_facets = []

  $scope.$watch('facets', function() {
    angular.forEach($scope.facets.grouped_brands, function(value, key) {
      $scope.brand_facets.push({brand: key, count: value})
    });
  });
})
Mahmoud M. Abdel-Fattah
  • 1,479
  • 2
  • 16
  • 34

2 Answers2

1

You can use angulars $broadcast and $on functionality to tell the second controller when the ajax answer is recieved.

How to exactly implement the broadcast feature depends on the relation between your controllers. You can use this SO-answer as help: $scope.$emit and .$on angularJS

Community
  • 1
  • 1
Daniel
  • 3,541
  • 3
  • 33
  • 46
0

It sounds like you have an asynchronous bug in your service. You either need to have the callback of the AJAX request return the data to the controllers, or use the $q to create a promise, which is returned to the controllers.

https://docs.angularjs.org/api/ng/service/$q

$q allows you to create a deferred object. So instead of the service returning a null object, it will return a promise that your controller can act on once it has been fulfilled.

Martin
  • 15,820
  • 4
  • 47
  • 56
  • 1
    I think an issue with this approach is one controller invokes the service method but the other controller won't know about it without being notified somehow so you'd need a deferred along with some sort of signaling like `$watch`. Also, assuming this could be called multiple times, you'd need to create and handle multiple deferred's as each one only handles a single resolve, I believe. – Manny D Jun 05 '14 at 13:57