简体   繁体   中英

Binding failing with associative array in angularJS

I'm trying to implement a Product Cart behavior, and I have a navigation bar which contains the Cart UI element. The service UserCart.js handles product add/remove. This service is used in NavController, which should get updated each time the Product is added or removed. All the UI bindings in Cart element work perfectly, except the portion which I'm binding to the associative array which contains the cart product information. Its key is Product ID, and value is an object {Quantity:Z, CostPerUnit: Y}

UserCart.js

(function() {
// Get reference to the app
var app = angular.module("jargoViewer");

// Create the factory that share the User Cart with various controllers
app.factory('UserCart', function(){
    var cart_items = [];
    var cart = {
        cart_val: 0,
        cart_size : 0,
        cart_products : [],
        cart_prod_ids : []
    };

    var addProductInCart = function(prodID, prodCostPerUnit, prodQuantity) {
        console.log('BEFORE Came inside addProductInCart total_cart_val:'+cart.cart_val);
        console.log('Came inside addProductInCart prod:'+prodID + ', costPerUnit:'+prodCostPerUnit+',quantity:' + prodQuantity);
        if((prodID in cart_items)) {
            // true if "prodID" exist in cart_items
            // Add the new prodID key element now
            prodObj = cart_items[prodID];
            prodObj.Quantity = prodObj.Quantity + prodQuantity;
            // TODO DELETE
            cartProdObj = cart.cart_products[prodID];
            cartProdObj.Quantity = cartProdObj.Quantity + prodQuantity;
        } else {
            // A product with same key doesnt exists
            cart_items[prodID] = {
                'Quantity' : prodQuantity,
                'CostPerUnit' : prodCostPerUnit
            };
            // TODO DELETE
            cart.cart_products[prodID] = {
                'Quantity' : prodQuantity,
                'CostPerUnit' : prodCostPerUnit
            };
        }
        // Add the total newly added products cost to Total Cart Value
        cart.cart_val += prodCostPerUnit * prodQuantity;
        cart.cart_size += 1;
        cart.cart_prod_ids.push(prodID);

        console.log('AFTER Came inside addProductInCart total_cart_val:'+cart.cart_val);
    };

    var removeProductInCart = function(prodID, prodQuantity) {
        if((prodID in cart_items)) {
            // true if "prodID" exist in cart_items
            // Add the new prodID key element now
            prodObj = cart_items[prodID];
            existingQuantity = prodObj.Quantity;
            prodCostPerUnit = prodObj.CostPerUnit;
            if(prodQuantity > existingQuantity) {
               alert('No more of this item exists in the cart!');
            } else {
                prodObj.Quantity = prodObj.Quantity - prodQuantity;
                // Add the total newly added products cost to Total Cart Value
                cart.cart_val -= prodCostPerUnit * prodQuantity;
                cart.cart_size -= 1;
                // TODO DELETE
                cartProdObj = cart.cart_products[prodID];
                cartProdObj.Quantity = cartProdObj.Quantity - prodQuantity;
                if(prodObj.Quantity < 1) {
                    // No more of this product left in cart, remove from cart list
                    cart_items.splice(prodID, 1);
                    // TODO DELETE
                    cart.cart_products.splice(prodID, 1);
                    cart.cart_prod_ids.splice(prodID, 1);
                }
            }
        } else {
            // Error
            alert('No more of this item exists in the cart!');
        }
    };

    // Return the Interface of UserCart
    return { 
        products_in_cart: cart_items,
        cart : cart,
        addProdInCart : addProductInCart,
        delProdInCart : removeProductInCart
    };
});

}());

The code for nav.html, and its controller NavController.js is as follows:

(function() {

var app = angular.module("jargoViewer");

var NavController = function($scope, UserCart) {
    $scope.userCart = UserCart.cart;
    $scope.cart_products = UserCart.products_in_cart;
};

app.controller("NavController", NavController);

}());

nav.html

<!-- Navigation -->
    <nav id="mainNav" class="navbar navbar-default navbar-fixed-top navbar-custom">
        <div class="container" ng-controller = "NavController">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header page-scroll">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                    <span class="sr-only">Toggle navigation</span> Menu <i class="fa fa-bars"></i>
                </button>
                <a class="navbar-brand" href="#page-top">Jargo Foods</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav navbar-right">
                    <li class="hidden">
                        <a href="#/main#page-top"></a>
                    </li>
                    <li class="page-scroll">
                        <a href="#/main#portfolio">Products</a>
                    </li>
                    <li class="page-scroll">
                        <a href="#/main#about">About</a>
                    </li>
                    <li class="page-scroll">
                        <a href="#/main#contact">Contact</a>
                    </li>
                    <!--
                    <li>                            
                        <p color:#fff>{{userCart.cart_val}} <i class="glyphicon glyphicon-shopping-cart" color:#fff></i></p>

                    </li>
                    -->
                    <li>
                        <div class="col-md-3">
                        <div id="cart" class="btn-group btn-block">
                            <button type="button" data-toggle="dropdown" class="btn btn-block btn-lg dropdown-toggle">
                                <i class="fa fa-shopping-cart"></i>
                                <span >Cart:</span> 
                                <span id="cart-total" ng-show ="userCart.cart_size">{{userCart.cart_size}} item(s) - ₹ {{userCart.cart_val}}</span>
                                <i class="fa fa-caret-down"></i>
                            </button>
                            <ul class="dropdown-menu pull-right">
                                <div >{{userCart.cart_products}}</div>
                                <div class="row" ng-repeat="(id, obj) in userCart.cart_products">{{id}} {{obj}}</div>
                                <div class="row" ng-repeat="obj in userCart.cart_prod_ids">{{obj}}</div>
                                <li>
                                    <table class="table table-striped hcart">
                                        <tbody>
                                            <tr ng-repeat="(id, itemObj) in cart_products">
                                                <td class="text-center">
                                                    <a href="product.html">
                                                        <img src="img/others/cart.png" alt="image" title="image" class="img-thumbnail img-responsive">
                                                    </a>
                                                </td>
                                                <td class="text-left">
                                                    <a href="product-full.html">
                                                        Seeds
                                                    </a>
                                                </td>
                                                <td class="text-right">x {{itemObj.Quantity}}</td>
                                                <td class="text-right">₹ {{itemObj.Quantity * itemObj.prodCostPerUnit}}</td>
                                                <td class="text-center">
                                                    <a href="#">
                                                        <i class="fa fa-times"></i>
                                                    </a>
                                                </td>
                                            </tr  >

                                    </tbody></table>
                                </li>
                                <li>
                                    <table class="table table-bordered total">
                                        <tbody>
                                            <tr>
                                                <td class="text-right"><strong>Sub-Total</strong></td>
                                                <td class="text-left">$1,101.00</td>
                                            </tr>
                                            <tr>
                                                <td class="text-right"><strong>Eco Tax (-2.00)</strong></td>
                                                <td class="text-left">$4.00</td>
                                            </tr>
                                            <tr>
                                                <td class="text-right"><strong>VAT (17.5%)</strong></td>
                                                <td class="text-left">$192.68</td>
                                            </tr>
                                            <tr>
                                                <td class="text-right"><strong>Total</strong></td>
                                                <td class="text-left">$1,297.68</td>
                                            </tr>
                                        </tbody>
                                    </table>
                                    <p class="text-right btn-block1">
                                        <a href="cart.html">
                                            View Cart
                                        </a>
                                        <a href="#">
                                            Checkout
                                        </a>
                                    </p>
                                </li>                                   
                            </ul>
                        </div>
                    </div>
                    </li>
                </ul>
            </div>
            <!-- /.navbar-collapse -->
        </div>
        <!-- /.container-fluid -->
    </nav>

Every binding works perfectly fine, except for the following:

<div >{{userCart.cart_products}}</div>
<div class="row" ng-repeat="(id, obj) in userCart.cart_products">{{id}} {{obj}}</div>

Please help figure what's wrong. Is there something special that needs to be done for associative array?

userCart.cart_products in your template does not refer to anything in your $scope.

Try this instead

var NavController = function($scope, UserCart) {
    $scope.userCart = UserCart.cart;
    $scope.userCart.cart_products = UserCart.products_in_cart;
};

You could also you simply expose UserCart in $scope :

var NavController = function($scope, UserCart) {
    $scope.userCart = UserCart;
};

and in your template

<div >{{userCart.cart_products}}</div>
<div class="row" ng-repeat="(id, obj) in userCart.products_in_cart">{{id}} {{obj}}</div>

Okay, I figured out the problem. Being a newbie to JS, I had trouble understanding how the Associative Array (or more precisely MAP in JS) is defined. What I was doing was still declaring the array and trying to use it as a MAP

    var cart = {
    cart_val: 0,
    cart_size : 0,
    cart_products : [],
    cart_prod_ids : []
};

The interesting part here is

cart_products : [],

This actually declares an ARRAY, and not a MAP. To fix the code, all I had to do was declare a MAP instead of array, all the other piece of code remaining the same!

cart_products : {},

This declares cart_products as a MAP, and then then the following would start to work

<div class="row" ng-repeat="(id, obj) in userCart.cart_products">{{id}} {{obj}}</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM