0

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!

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

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

});

2 Comments

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?
You can watch any function whether its on the scope or not

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.