0

I have a parent shell html file that has an icon to update the number of products in the cart. The number is supposed to be retrieved from a factory.

angular
    .module('awesome')
    .factory('ProductFactory', productFactory);
     function productFactory($log) {
     var factory = {
        addCartProducts: addCartProducts,
        getCartCount: getCartCount
    },
    cartProducts = [];

    return factory;

    function addCartProducts(product)
    {
        cartProducts.push(product);
        getCartCount();
        $log.info(cartProducts.length);
    }
    function getCartCount() {
        return cartProducts.length;
    }
}

In the parent controller I have an scope value being pulled from

$scope.count = ProductFactory.getCartCount()

In the child controller I'm adding to the cart

$scope.addToCart = function (product) {
    ProductFactory.addCartProducts(product);
};

However when I add to the cart, I can see in the log that they are being added, however, the item in the parent controller does not update. What am I missing?

Jon Harding
  • 4,928
  • 13
  • 51
  • 96
  • 3
    What is the code snippet for parent controller? – ABOS May 14 '15 at 19:33
  • sorry I called it 'shell' controller, which is the parent snippet – Jon Harding May 14 '15 at 19:36
  • How does shell controller knows child has updated. You are not showing us the relevant code i believe. – PSL May 14 '15 at 19:37
  • That is all the code I have, which is why I posed the question. Do I need to use $rootScope.$broadcast? – Jon Harding May 14 '15 at 19:38
  • The parent is holding onto a number (the count), it will have to update the number every time that the child gains an item. So, like, the parent might have to do something like `$scope.$watch(function(){ return ProductFactory.getCartCount(); }, useTheNewCount);` - not that I would suggest doing that (calling the function on every `$digest` cycle is overkill for this - you want to do things differently). – DRobinson May 14 '15 at 19:39
  • @DRobinson Do you have a suggestion as to what direction to go? – Jon Harding May 14 '15 at 19:41
  • Use eventing.. and if u really need a full fledged pattern.. flux is a better one – PSL May 14 '15 at 19:43
  • Well for one thing, your Factory seems to be more of a Service. You aren't using it to create different carts, if you inject it multiple places they'll share cartProducts. That seems like the first issue. If you fix that, expose the `cartProducts` in it, and do something like `$scope.cart = ProductFactory.create();`, then you can `$scope.$watchCollection('cart.cartProducts', doSomething)`. Or in your views you would be able to do `{{cart.cartProducts.length}}`, etc. If you need to keep the variable private, consider exposing the count in the object (no function). Otherwise `$emit`/`$broadcast` – DRobinson May 14 '15 at 19:47
  • One ugly solution is to use $parent when call addTocart in child controller, but it is not a good practice. – ABOS May 14 '15 at 19:49
  • Not sure but try this answer if it gives you [some direction](http://stackoverflow.com/questions/25274563/angularjs-communication-between-directives/25274665#25274665) and i wouldn't use a watch or watch collection – PSL May 14 '15 at 19:55
  • @PSL I'm actually using the controllerAs pattern, so I don't have $scope injected into the controller, do I need to inject $scope to use what you listed? – Jon Harding May 14 '15 at 19:58
  • 2
    @JonHarding yes for any eventing even with the angular built-in one ($emit/$broadcast)you need to inject scope. Else you can build a factory for pub/sub with subscribe/publish and inject them as required but remember to unregister when out of scope to avoid any memory leak, the one i answered (linked) i am using scope.$destory to automatically unregister them. – PSL May 14 '15 at 19:59

1 Answers1

0

The reason why your count is not updating is because you set it to the value returned by ProductFactory.getCartCount(). If you make further changes to $scope.count in the controller, then the updates will occur, but further changes to ProductFactory.getCartCount() won't. Here is something that you could do:

Parent controller:

$scope.getCount() = function () {
    return ProductFactory.getCartCount();
}

and in your view, instead of using {{count}}, use {{getCount()}}

I hope this helps!

bamboo_inside
  • 462
  • 4
  • 15
  • 2
    This isn't a good practice though.. IMHO... This is as good as adding a watch on `ProductFactory.getCartCount()`. But what if OP is not just displaying the count on the view, instead looking to do something when an item has been added. – PSL May 14 '15 at 20:16
  • 1
    hmmm... as you mentioned, this wouldn't be ideal if OP wants to manipulate the count from the parent controller as well... but if that's the case, OP would be better off with a directive that listens to $broadcasts, instead of having this code in the controller. – bamboo_inside May 14 '15 at 20:25
  • 1
    Yup i am with you on that. Build a component(directive) with its own controller, listen to the event from the directive and invoke respective controller method. – PSL May 14 '15 at 20:27