user791134 user791134 - 6 months ago 21
AngularJS Question

How to Add a product to the cart and then update the quantity from both the product page and from the cart itself.

I am completely stumped on how to achieve something specific that the below website has achieved. Does anyone know how to update the quantity of a product from the product details page to the shopping cart, and have that quantity shared/bound between the cart and and the product details page for each an every product repeated from a collection. (I am not talking about simply having a global cart quantity total via a simple custom directive). Please see the link below. Add a product to the cart and then update the quantity from both the product page and from the cart itself. This is what I am trying to achieve. Thank you all in advance!

http://demo.shopnx.in/

Lex Lex
Answer

Typically you'll get better responses if you post some code that you have tried and then ask to be guided on where you are going wrong. I've created a simple JSFiddle to demonstrate one method of doing this. It is extremely simple, contrived, not production worthy by any stretch of the imagination and doesn't really do much, but it should show you one construct that will allow you to accomplish the functionality you're after.

The key is to use some type of shared storage so that the same array of items is available to both your product listing and the cart. In the sample I have done this using a Value:

.value('cartStorage', {
    items: []
})

This value is then injected in the main controller:

.controller('mainController', function(cartStorage) {
    var _this = this;
    _this.cartStorage = cartStorage;

    _this.items = [{
        name: 'Apple',
        price: .5,
        quantity: 0,
        showAddToCart: false,
        addedToCart: false
    }, {
        name: 'Orange',
        price: .5,
        quantity: 0,
        showAddToCart: false,
        addedToCart: false
    }, {
        name: 'Grapes',
        price: 1,
        quantity: 0,
        showAddToCart: false,
        addedToCart: false
    }];

    _this.addToCart = function(item) {
        _this.cartStorage.items.push(item);
        item.addedToCart = true;
    }

    _this.increaseItemAmount = function(item) {
        item.quantity++;
        item.showAddToCart = true;
    }

    _this.decreaseItemAmount = function(item) {
        item.quantity--;
        if (item.quantity <= 0) {
            item.quantity = 0;
            item.addedToCart = false;
            item.showAddToCart = false;
            var itemIndex = _this.cartStorage.items.indexOf(item);
            if (itemIndex > -1) {
                _this.cartStorage.items.splice(itemIndex, 1);
            }
        } else {
            item.showAddToCart = true;
        }
    }
})

As well as the cart controller:

.controller('cartController', function(cartStorage) {
    var _this = this;
    _this.cartStorage = cartStorage;

    _this.increaseItemAmount = function(item) {
        item.quantity++;
    }

    _this.decreaseItemAmount = function(item) {
        item.quantity--;
        if (item.quantity <= 0) {
            item.quantity = 0;
            item.addedToCart = false;
            item.showAddToCart = false;
            var itemIndex = _this.cartStorage.items.indexOf(item);
            if (itemIndex > -1) {
                _this.cartStorage.items.splice(itemIndex, 1);
            }
        }
    }

    _this.removeFromCart = function(item) {
        item.quantity = 0;
        item.addedToCart = false;
        item.showAddToCart = false;
        var itemIndex = _this.cartStorage.items.indexOf(item);
        if (itemIndex > -1) {
            _this.cartStorage.items.splice(itemIndex, 1);
        }
    }
})

Now the cartStorage object is shared so any update made in one controller will automagically be reflected in the other controller. All that's left is the markup:

<div ng-app="app">
    <div ng-controller="mainController as main">
        <h2>Main Controller</h2>
        <div>
            <table>
                <tr>
                    <td>Item</td>
                    <td>Price</td>
                    <td>Quantity</td>
                    <td></td>
                </tr>
                <tr ng-repeat="item in main.items">
                    <td>{{item.name}}</td>
                    <td>{{item.price | currency}}</td>
                    <td>{{item.quantity}}</td>
                    <td>
                        <button ng-click="main.increaseItemAmount(item)">+</button>
                        <button ng-click="main.decreaseItemAmount(item)">-</button>
                        <button ng-click="main.addToCart(item)" ng-show="item.showAddToCart && !item.addedToCart">Add to Cart</button>
                    </td>
                </tr>
            </table>
        </div>
    </div>
    <div ng-controller="cartController as cart">
        <h2>Cart Controller</h2>
        <div>
            <table>
                <tr>
                    <td>Item</td>
                    <td>Price</td>
                    <td>Quantity</td>
                    <td></td>
                </tr>
                <tr ng-repeat="item in cart.cartStorage.items">
                    <td>{{item.name}}</td>
                    <td>{{item.price | currency}}</td>
                    <td>{{item.quantity}}</td>
                    <td>
                        <button ng-click="cart.increaseItemAmount(item)">+</button>
                        <button ng-click="cart.decreaseItemAmount(item)">-</button>
                        <button ng-click="cart.removeFromCart(item)">Remove from Cart</button>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</div>

Update showing the usage of a Factory instead of Value

Instead of using a Value use this service:

.factory('cartStorage', function() {
    var _cart = {
        items: []
    };
    var service = {
        get cart() {
            return _cart;
        }
    }
    return service;
})

Then modify the code in the controllers to use the .cart property of the service instead of the value. You only need to change one line of code in both controllers. Change:

_this.cartStorage = cartStorage;

to:

_this.cartStorage = cartStorage.cart;

Here is an updated JSFiddle.