Angular Shopping Cart

Angular Shopping cart

So one of the best things with angular is that it is really easy to understand the concepts and you build your app really fast. Starting with angular it is usually popular to create a Todo app as your first project but I thought I would showcase building a shopping cart instead. Just to be special 😉

This post assumes you understand the concepts presented inhttps://swedecoder.wordpress.com/2014/12/16/angularjs-starting-out/

The parts

The app will build everything into one controller. This is not really how you want to do it on an enterprise level but we have to start somewhere right?

The parts of the app will consist of

  • Products to choose from
  • A shopping cart that displays the chosen product

It should be possible to edit the shopping cart. It should also display the total sum

Bootstrapping

<script type="text/javascript" src="angular.js">
<script>
    var app = angular.module('app',[]);
</script>

The controller

app.controller('shoppingCtrl',function($scope){
    $scope.products = [];
    $scope.cartItems = [];

    function initProducts(){
        $scope.products = [
            { name : 'CD', price : 110, id : 1 },
            { name : 'DVD', price : 150, id: 2 }
        ]
    }


    initProducts();

    $scope.addCartItem = function(product){
        $scope.cartItems.push({ name : product.name, quantity: 1, id : product.id, price : product.price })
    }

    $scope.cartSum = function(){
        var sum =0;
        $scope.cartItems.forEach(function(item){
            sum += item.quantity * item.price;
        });

        return sum;
    }
})

So at this point we support add but we will support interactions on the cart later on.

The view

<div ng-app="app">
    <div ng-controller="shoppingCtrl">
        <h2>Products</h2>
        <table ng-show="products.length > 0">
            <tr ng-repeat="product in products">
                <td>
                    {{product.name}}
                </td>   
                <td>
                    {{product.price}}
                </td>   
                <td>
                    <button ng-click="addCartItem(product)" ></button>
                </td>
            </tr>
        </table>

        <h2>Shopping cart</h2>
            <table ng-show="cartItems.length > 0">
            <tr>
                <th>Name</th>
                <th>Price</th>
                <th>Quantity</th>
            </tr>
            <tr ng-repeat="item in cartItems">
                <td>
                    {{item.name}}
                </td>   
                <td>
                    {{item.price}}
                </td>   
                <td>
                    {{item.quantity}}
                </td>
            </tr>
            <tr>
                <td>
                    {{ cartSum() }}
                </td>
            </tr>
        </table>
    </div>
</div>

So here we render out the products and an add button as well as the cart. We also introduce some new directives

  • ng-show. is a directive that takes a boolean that determines wether this element should show or not.
  • ng-repeat. is a looping directive that lets you loop a list.

Making it smarter

So it isn’t very smart, our cart application. The biggest problem is that if we try to add the same product again we get a NEW row. Sure the sum is correct but we would rather it just updated the quantity. So how?

We add some logic
in the controller :

app.controller('shoppingCtrl',function($scope){
    $scope.products = [];
    $scope.cartItems = [];

    function initProducts(){
        $scope.products = [
            { name : 'CD', price : 110, id : 1 },
            { name : 'DVD', price : 150, id: 2 }
        ]
    }


    initProducts();

    $scope.addCartItem = function(product){
        var existingItem = getExistingCartItem(product.id);
        if(existingItem == null){
            $scope.cartItems.push({ name : product.name, quantity: 1, id : product.id, price : product.price })
        }else{
            existingItem.quantity++;
        }


    }

    function getExistingCartItem(id){
        for(var i=0; i< $scope.cartItems.length; i++){
            if($scope.cartItems[i].id === id){
                return $scope.cartItems[i];
            }
        }

        return null;
    }

    $scope.cartSum = function(){
        var sum =0;
        $scope.cartItems.forEach(function(item){
            sum += item.quantity * item.price;
        });

        return sum;
    }
})

Ok so we added a method

function getExistingCartItem(id){
        for(var i=0; i< $scope.cartItems.length; i++){
            if($scope.cartItems[i].id === id){
                return $scope.cartItems[i];
            }
        }

        return null;
    }

To find out wether we added this before

Also we changed the existing add-method

$scope.addCartItem = function(product){
        var existingItem = getExistingCartItem(product.id);
        if(existingItem == null){
            $scope.cartItems.push({ name : product.name, quantity: 1, id : product.id, price : product.price })
        }else{
            existingItem.quantity++;
        }


}

To check for an existing item.

Edit cart

So at this point we dont have any way to edit the cart. We would like a way to:

  • increase items in the cart
  • decrease items
  • remove item completely if decreased to 0
increase item in cart

Controller

$scope.increase = function(item){
    item.quantity++;
}

View

    <h2>Shopping cart</h2>
            <table ng-show="cartItems.length > 0">
            <tr>
                <th>Name</th>
                <th>Price</th>
                <th>Quantity</th>
                <th>&nbsp;</th>
            </tr>
            <tr ng-repeat="item in cartItems">
                <td>
                    {{item.name}}
                </td>   
                <td>
                    {{item.price}}
                </td>   
                <td>
                    {{item.quantity}}
                </td>
                <td> <button ng-click="increase(item)">+</button> </td>
            </tr>
            <tr>
                <td>
                    {{ cartSum() }}
                </td>
            </tr>
        </table>

With the added row being

<td> <button ng-click="increase(item)">+</button> </td>
decrease item

Controller

function getItemIndex(item){
    for(var i=0; i< $scope.cartItems.length; i++){
        if($scope.cartItems[i].id === item.id){
            return i;
        }
    }

    return -1;
}

$scope.decrease = function(item){
    var index = getItemIndex(index);
    if(item.quantity -1 === 0){
        $scope.cartItems.splice(index,1);
    }
}

View

<td> 
    <button ng-click="increase(item)">+</button> 
    <button ng-click="decrease(item)">-</button>
</td>

Add filtering

The idea with filtering is that our product list may be very long and that our add process should be made easier

For this to work we only need to change things on view level. We need to add the following at the top

<div ng-app="app">
    <div ng-controller="shoppingCtrl">
        <h2>Products</h2>

        <input type="text" ng-model="productName" />
        <table ng-show="products.length > 0">
            <tr ng-repeat="product in products | filter:'productName'">
                <td>
                    {{product.name}}
                </td>   
                <td>
                    {{product.price}}
                </td>   
                <td>
                    <button ng-click="addCartItem(product)" ></button>
                </td>
            </tr>
        </table>

So added part are the input field

<input type="text" ng-model="productName" />

And the filter pipe to ng-repeat

<tr ng-repeat="product in products | filter:'productName'">  // | filter:'productName'

Finally

The complete code becomes

<script type="text/javascript" src="angular.js">
<script>
    var app = angular.module('app',[]);


    app.controller('shoppingCtrl',function($scope){
        $scope.products = [];
        $scope.cartItems = [];

        function initProducts(){
            $scope.products = [
                { name : 'CD', price : 110, id : 1 },
                { name : 'DVD', price : 150, id: 2 }
            ]
        }


        initProducts();

        $scope.addCartItem = function(product){
            $scope.cartItems.push({ name : product.name, quantity: 1, id : product.id, price : product.price })
        }

        function getItemIndex(item){
            for(var i=0; i< $scope.cartItems.length; i++){
                if($scope.cartItems[i].id === item.id){
                    return i;
                }
            }

            return -1;
        }

        $scope.decrease = function(item){
            var index = getItemIndex(index);
            if(item.quantity -1 === 0){
                $scope.cartItems.splice(index,1);
            }
        }

        $scope.cartSum = function(){
            var sum =0;
            $scope.cartItems.forEach(function(item){
                sum += item.quantity * item.price;
            });

            return sum;
        }

        $scope.increase = function(item){
            item.quantity++;
        }
    })

</script>

And the view

<div ng-app="app">
    <div ng-controller="shoppingCtrl">
        <h2>Products</h2>

        <input type="text" ng-model="productName" />
        <table ng-show="products.length > 0">
            <tr ng-repeat="product in products | filter:'productName'">
                <td>
                    {{product.name}}
                </td>   
                <td>
                    {{product.price}}
                </td>   
                <td>
                    <button ng-click="addCartItem(product)" ></button>
                </td>
            </tr>
        </table>

        <h2>Shopping cart</h2>
            <table ng-show="cartItems.length > 0">
            <tr>
                <th>Name</th>
                <th>Price</th>
                <th>Quantity</th>
                <th>&nbsp;</th>
            </tr>
            <tr ng-repeat="item in cartItems">
                <td>
                    {{item.name}}
                </td>   
                <td>
                    {{item.price}}
                </td>   
                <td>
                    {{item.quantity}}
                </td>
                <td> 
                    <button ng-click="increase(item)">+</button> 
                    <button ng-click="decrease(item)">-</button>
                </td>
            </tr>
            <tr>
                <td>
                    {{ cartSum() }}
                </td>
            </tr>
        </table>
    </div>
</div>

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s