Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I have a shopping cart that shows the name of the flavor and quantity, then the total $ of each flavor. Then at the bottom of all the flavor, I have the calculation of the entire shopping cart.

HTML:

<div ng-repeat="flavor in cart track by $index">
 <div>
   <span class="flavor-name no-margin">{{flavor.name}} x <input type="text" name="{{flavor.name}}" size="1" ng-model="flavor.quantity"></span>
   <span class="flavor-price no-margin">{{flavor.price * flavor.quantity | currency }}</span>
   <div class="clearfix"></div>
   </div>
</div>

<div ng-if="cart.length > 0">
  <span class="cart-total-text no-margin">Total:</span>
  <span class="cart-total no-margin">{{ total | currency}}</span>
  <div class='clearfix'></div>
</div>

In my Controller:

function total() {
   var total = 0;
   for (var i = 0; i < $scope.cart.length; i++) {
     var add = $scope.cart[i].price * $scope.cart[i].quantity;
     total = total + add;
   }

  return total;
}

$scope.$watchCollection("cart", function() {
  $scope.total = total();
});

And my cart looks like this: { 'name': 'Strawberry', 'price': 4.5, 'quantity': 0, }, { 'name': 'Mint', 'price': 3.5, 'quantity': 0, }, etc

Right now, the total is working for when I add new things to the cart, but how do I make angular "listen" to when the quantity of the flavor is changed in my input box? Thanks!

share|improve this question
up vote 1 down vote accepted

You should be able to put the total() function on the scope and bind it to the span:

In the HTML:

<span class="cart-total no-margin">{{total() | currency}}</span>

In the controller:

$scope.total = function() {
    var total = 0;
    for (var i = 0; i < $scope.cart.length; i++) {
        var add = $scope.cart[i].price * $scope.cart[i].quantity;
        total = total + add;
    }
    return total;
}

Whenever something changes (like the quantity), Angular should trigger a digest cycle and reevaluate all the bound expressions including the total() method.

IMO that's the easiest way. If you really want to go with the $watch route (or understand why your current code is not working) you have to understand how Angular "watches" objects.

  • $scope.$watch by defaults only fires when the reference of the object changes.

  • $scope.$watchCollection goes a little further and fires when elements are added or removed from a collection (even though the collection reference stays the same).

In your case, changing the quantity of a flavor does not add or remove an item in the collection, which is why your code isn't triggered.

What you really want is a "deep watch" of the cart object. That can be achieved by passing a 3rd argument to the $watch method (a boolean called objectEquality):

$scope.$watch("cart", function() {
    $scope.total = total();
}, true); // Tells Angular to test object equality.

This will make Angular look for change in the properties of the watched object (not just the reference), which should fire when the flavor.quantity changes.

share|improve this answer

You can watch a function if it is in the scope.

$scope.$watch('total()', function(){

});
share|improve this answer
    
Hello, can you please elaborate a little bit on this? I am an angular noobie. What do I put between the { }? Do I delete the $watch.collection call I already have? – boo Aug 3 '14 at 1:13
    
You can watch any function whether its on the scope or not – Charlie Martin Jun 15 '15 at 20:50

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.