var app = angular.module('myCart', []);
<!DOCTYPE html>
<html ng-app="myCart">
<head>
<meta charset="utf-8" />
<title>Shopping Cart module</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js@1.5.x" src="https://code.angularjs.org/1.5.8/angular.js" data-semver="1.5.8"></script>
<script src="app.js"></script>
<script src="cartService.js"></script>
<script src="cartCtrl.js"></script>
</head>
<body ng-controller="CartCtrl" id="container">
<div class="table container-margin">
<div class="row" id="title">
<div class="normal-view data divider-bottom">
<div class="">
<h1>Your Shopping Bag</h1>
</div>
</div>
<div class="small-device-view thick-divider-bottom spacing">
<div class="data col8 align-left">
Your Shopping Bag
</div>
<div class="data col2 align-right" >
{{totalItems}} ITEMS
</div>
</div>
</div>
<div class="row">
<div class="normal-view table thick-divider-bottom spacing">
<div class="row ">
<div class="data col7 align-left" > {{totalItems}} ITEMS</div>
<div class="data col1">SIZE</div>
<div class="data col1">QTY</div>
<div class="data col1">PRICE</div>
</div>
</div>
</div>
<div class="row" ng-repeat="prod in prods" >
<div class="table" ng-class="{'thick-divider-bottom':$last,'divider-bottom':!$last}">
<div class="row " >
<div class="data col3 align-left">
<img ng-src={{prod.p_img}} alt="prod.p_name"/>
</div>
<div class="data col7 valign-middle">
<div class="table">
<div class="row prod-spec">
<div class="data col6 align-left">
<div class="uppercase">{{prod.p_variation}} {{prod.p_name}}</div>
<div class="dim">Style #: {{prod.p_style}}</div>
<div class="dim">Color: {{prod.p_selected_color.name}} </div>
<div class="dim small-device-view uppercase">Size: {{prod.p_selected_size.code}}</div>
<div class="small-device-view spacing">QTY:<input type="text" class="qty" size="1" ng-model="prod.p_quantity" ng-change="reCalculate(prod.p_quantity,$index)"/></div>
<div class="small-device-view spacing big-font"><span>{{prod.c_currency}}</span><span ng-bind="prod.p_quantity * prod.p_price"></span></div>
</div>
<div class="normal-view data col1 uppercase">{{prod.p_selected_size.code}}</div>
<div class="normal-view data col1"><input type="text" class="qty" size="1" ng-model="prod.p_quantity" ng-change="reCalculate(prod.p_quantity,$index)"/></div>
<div class="normal-view data col2" ><span>{{prod.c_currency}}</span><span ng-bind="prod.p_quantity * prod.p_price"></span></div>
</div>
<div class="row normal-view">
<div class="dim data col5 align-left">EDIT | X Remove | Save For Later</div>
</div>
</div>
</div>
</div>
<div class="small-device-view row spacing">
<div class="dim data col10 align-left">EDIT | X Remove | Save For Later</div>
</div>
</div>
<div class= "normal-view" ng-if="$last">
<div id="left-section">
<p><b>Need help or have questions?</b></p>
<p>Call Customer Service <br/>
at 1-800-555-5555</p>
<p><a href="#">Chat with one of our stylists</a></p>
<p><a href="#">See return & Exchange Policy</a></p>
</div>
<div id="right-section" class="container-margin">
<div class="table ">
<div class="row promo-code spacing">
<div class="data col4 align-left ">
Enter Promotion code or Gift Card
</div>
<div class="data col4">
<input type="text" placeholder="code" ng-model="code" />
</div>
<div class="data col2">
<button class="btn" ng-click="applyCode(code)">APPLY</button>
</div>
</div>
<div class="row spacing">
<div class="data col4 align-left ">
<p>SUBTOTAL</p>
</div>
<div class="data col4 ">
</div>
<div class="data col4" ng-bind="'$' + subTotal">
</div>
</div>
<div class="row spacing">
<div class="data col4 align-left ">
<p ng-show="discount > 0">PROMOTION CODE <b>{{code}}</b> APPLIED</p>
<p ng-show="discount === 0">NO PROMOTION CODE APPLIED</p>
</div>
<div class="data col4 ">
</div>
<div class="data col4" ng-bind="'-$'+ discount">
</div>
</div>
<div class="row divider-bottom spacing">
<div class="data col4 align-left ">
<p>ESTIMATED SHIPPING*</p>
<p>You Qualify for for Free shipping,<br/>
because your order is over $50*</p>
</div>
<div class="data col4 ">
</div>
<div class="data col4 ">
FREE
</div>
</div>
<div class="row thick-divider-bottom spacing">
<div class="data col4 align-left ">
<p>ESTIMATED TOTAL</p>
<p>Tax will be applied during checkout</p>
</div>
<div class="data col4 ">
</div>
<div class="data col4" ng-bind="'$' + estTotal">
</div>
</div>
<div class="row spacing">
<div class="data col4">
</div>
<div class="data col4 ">
<a href="#">CONTINUE SHOPPING</a>
</div>
<div class="data col4 ">
<input type="button" value="CHECKOUT" class="btn"/>
</div>
</div>
</div>
<p class="align-right">
<img src="http://imgur.com/bqcZgOZ.jpeg" alt="secure-checkout">Secure checkout.
Shopping is always safe and secure
</p>
</div>
</div>
<div class="small-device-view " ng-if="$last">
<div class="table ">
<div class="row ">
<div class="data big-font extra-spacing">ENTER PROMOTION CODE OR GIFT CARD</div>
</div>
<div class="row data extra-spacing">
<input type="text" placeholder="code" ng-model="code" />
<button class="btn" ng-click="applyCode(code)">APPLY</button>
</div>
</div>
<div class="table ">
<div class="row extra-spacing">
<div class="data col6 align-left ">
<p>SUBTOTAL</p>
</div>
<div class="data col4" ng-bind="'$' + subTotal">
</div>
</div>
<div class="row extra-spacing">
<div class="data col6 align-left ">
<p ng-show="discount > 0">PROMOTION CODE <b>{{code}}</b> APPLIED</p>
<p ng-show="discount === 0">NO PROMOTION CODE APPLIED</p>
</div>
<div class="data col4" ng-bind="'-$'+ discount">
</div>
</div>
<div class="row divider-bottom extra-spacing">
<div class="data col6 align-left ">
<p>ESTIMATED SHIPPING*<br/>
<span class="dim">You Qualify for for Free shipping,<br/>
because your order is over $50*</span> </p>
</div>
<div class="data col4 ">
FREE
</div>
</div>
<div class="row spacing">
<div class="data col6 align-left ">
<p>ESTIMATED TOTAL<br/>
<span class="dim">Tax will be applied during checkout</span></p>
</div>
<div class="data col4" ng-bind="'$' + estTotal">
</div>
</div>
</div>
<div class="table">
<div class="row extra-spacing">
<div class="data col4 ">
<input type="button" value="CHECKOUT" class="btn"/>
</div>
</div>
<div class="row extra-spacing">
<div class="data col10 ">
<a href="#">CONTINUE SHOPPING</a>
</div>
</div>
<div class="row extra-spacing">
<div class="data col10 ">
<p>Secure checkout.
Shopping is always safe and secure</p>
</div>
</div>
<div class="row">
<div class="data col10 ">
<img src="http://imgur.com/bqcZgOZ.jpeg" alt="secure-checkout">
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
/* Smartphones (portrait and landscape) -----------*/
@media screen and (max-width : 480px) {
/* Styles */
#container .table .normal-view {
display: none;
}
#container .table .small-device-view {
display:block;
}
#container .table .row {
font-size :10px;
}
#container #title {
height :20px;
}
#container button{
font-size:10px;
}
}
.table .row{
font-family: serif;
font-size :12px;
}
.normal-view {
/*display:block;*/
width:100%;
}
#container .small-device-view {
display:none;
}
/* Styles for desktops*/
/*@media screen and (min-device-width : 992px) and (max-device-width : 1224px) {
.normal-view {
display:block;
}
.small-device-view {
display:none;
}
}
*/
.table {
display:table;
width :100%;
}
.table .row {
display:table-row;
width :100%;
}
.table .row .data{
display:table-cell;
padding-left:3px;
padding-right:3px;
}
.table .row .col10 {
width :100%;
}
.table .row .col3 {
width :30%;
}
.table .row .col6 {
width :60%;
}
.table .row .col4 {
width :40%;
}
.prod-image {
height :200px;
}
.table .row .col2 {
width :20%;
}
.table .row .col8 {
width :80%;
}
.table .row .col7 {
width :70%;
}
.table .row .col1 {
width :10%;
}
.container-margin {
margin :10px;
}
.divider-bottom {
border-bottom :1px solid grey;
}
.thick-divider-bottom {
border-bottom :3px solid darkgrey;
}
#title {
height :100px;
}
.table .row .align-left{
text-align:left;
}
.table .prod-spec{
height :80px;
}
.data {
text-align:center;
}
#left-section {
width: 30%;
position:absolute;
}
#right-section {
left: 30%;
position:absolute;
}
.table #right-section .promo-code {
height : 10px;
}
.align-right {
text-align: right;
}
.spacing {
padding-top :5px;
padding-bottom:5px;
}
.extra-spacing {
padding-top :10px;
padding-bottom:10px;
}
.table .row .valign-middle {
vertical-align:middle;
}
.dim {
color:lightgrey;
}
.big-font {
font-size:12px;
}
.uppercase {
text-transform: uppercase;
}
.btn {
background: #3498db;
background-image: -webkit-linear-gradient(top, #3498db, #2980b9);
background-image: -moz-linear-gradient(top, #3498db, #2980b9);
background-image: -ms-linear-gradient(top, #3498db, #2980b9);
background-image: -o-linear-gradient(top, #3498db, #2980b9);
background-image: linear-gradient(to bottom, #3498db, #2980b9);
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
font-family: Arial;
color: #ffffff;
font-size:12px;
/*padding: 10px 20px 10px 20px;*/
text-decoration: none;
}
.btn:hover {
background: #3cb0fd;
background-image: -webkit-linear-gradient(top, #3cb0fd, #3498db);
background-image: -moz-linear-gradient(top, #3cb0fd, #3498db);
background-image: -ms-linear-gradient(top, #3cb0fd, #3498db);
background-image: -o-linear-gradient(top, #3cb0fd, #3498db);
background-image: linear-gradient(to bottom, #3cb0fd, #3498db);
text-decoration: none;
}
app.controller('CartCtrl', function($scope,CartService) {
var noOfProducts =0;
var priceQtyArr =[];
$scope.prods=[];
$scope.code="";
$scope.totalItems =0;
$scope.subTotal = 0;
$scope.estTotal = 0;
$scope.discount = 0;
$scope.reCalculate =function (newQty, index) {
var priceQtyObj = priceQtyArr[index];
var prevQty = priceQtyObj.qty;
var prevTProdPrice = priceQtyObj.price * prevQty;
var incOrDecQty =0;
var incOrDecPrice = 0;
var newTProdPrice = priceQtyObj.price * newQty;
priceQtyArr[index].qty = newQty;
incOrDecQty = newQty - prevQty;
incOrDecPrice = newTProdPrice - prevTProdPrice;
$scope.totalItems += incOrDecQty; //update total items on qty change
$scope.subTotal += incOrDecPrice; //updated subtotal on qty change
$scope.estTotal = $scope.subTotal - $scope.discount ;
};
$scope.applyCode = function (code) {
var disc = 0;
if(code === "magic3"){
if($scope.totalItems < 3){
disc = 0;
}
else if ($scope.totalItems === 3){
disc = $scope.subTotal * 0.05;
}
else if ($scope.totalItems > 3 && $scope.totalItems <= 6){
disc = $scope.subTotal * 0.10;
}else if($scope.totalItems > 10){
disc = $scope.subTotal * 0.25;
}
}
$scope.discount = disc;
$scope.estTotal = $scope.subTotal - $scope.discount ;
};
function updateTotal (){
for(var i=0;i<noOfProducts;i++){
var q = parseInt($scope.prods[i].p_quantity,10);
var p = parseInt($scope.prods[i].p_price,10);
$scope.subTotal += p;
var obj = {
'qty' : q,
'price': p
};
priceQtyArr.push(obj);
$scope.totalItems += q;
}
$scope.estTotal = $scope.subTotal - $scope.discount ;
}
//fetch the products & its details
CartService.$getProductsInCart().
then(function (response){
//angular.copy(response.data.productsIncart, $scope.prods);
$scope.prods = response.data.productsInCart;
noOfProducts = $scope.prods.length;
updateTotal();
});
});
{
"productsInCart": [{
"p_id": "1",
"p_name": "cotton tshirt",
"p_variation": "solid green",
"p_style": "ms13kt1906",
"p_img":"http://imgur.com/zGcrz78.jpeg",
"p_selected_color": {
"name": "blue",
"hexcode": "#1169BD"
},
"p_selected_size": {
"name": "small",
"code": "s"
},
"p_available_options": {
"colors": [{
"name": "green",
"hexcode": "#A3D2A1"
}, {
"name": "yellow",
"hexcode": "#F9F8E6"
}, {
"name": "red",
"hexcode": "#ED99A8"
}],
"sizes": [{
"name": "small",
"code": "s"
}, {
"name": "medium",
"code": "m"
}, {
"name": "large",
"code": "l"
}, {
"name": "extra large",
"code": "xl"
}]
},
"p_quantity": 1,
"p_originalprice": 11.0,
"p_price": 11.0,
"c_currency": "$"
}, {
"p_id": "2",
"p_name": "print girls tee",
"p_variation": "pink rainbow",
"p_style": "ms13kt1906",
"p_img":"http://imgur.com/Hjfrn56.jpeg",
"p_selected_color": {
"name": "pink",
"hexcode": "#F1DDEF"
},
"p_selected_size": {
"name": "small",
"code": "s"
},
"p_available_options": {
"colors": [{
"name": "green",
"hexcode": "#A3D2A1"
}, {
"name": "yellow",
"hexcode": "#F9F8E6"
}, {
"name": "pink",
"hexcode": "#F1DDEF"
}],
"sizes": [{
"name": "small",
"code": "s"
}, {
"name": "medium",
"code": "m"
}, {
"name": "large",
"code": "l"
}, {
"name": "extra large",
"code": "xl"
}]
},
"p_quantity": 1,
"p_originalprice": 17.0,
"p_price": 17.0,
"c_currency": "$"
}, {
"p_id": "3",
"p_name": "flower pattern shirt",
"p_variation": "blue",
"p_style": "ms13kt1906",
"p_img":"http://imgur.com/EpT67f4.jpeg",
"p_selected_color": {
"name": "blue",
"hexcode": "#1169BD"
},
"p_selected_size": {
"name": "small",
"code": "s"
},
"p_available_options": {
"colors": [{
"name": "green",
"hexcode": "#A3D2A1"
}, {
"name": "blue",
"hexcode": "#1169BD"
}, {
"name": "red",
"hexcode": "#ED99A8"
}],
"sizes": [{
"name": "small",
"code": "s"
}, {
"name": "medium",
"code": "m"
}, {
"name": "large",
"code": "l"
}, {
"name": "extra large",
"code": "xl"
}]
},
"p_quantity": 1,
"p_originalprice": 21.0,
"p_price": 9.0,
"c_currency": "$"
}, {
"p_id": "4",
"p_name": "check pattern tshirt",
"p_variation": "mens red",
"p_style": "ms13kt1906",
"p_img":"http://imgur.com/G6t80Rc.jpeg",
"p_selected_color": {
"name": "red",
"hexcode": ""
},
"p_selected_size": {
"name": "small",
"code": "s"
},
"p_available_options": {
"colors": [{
"name": "green",
"hexcode": "#A3D2A1"
}, {
"name": "yellow",
"hexcode": "#F9F8E6"
}, {
"name": "red",
"hexcode": "#ED99A8"
}],
"sizes": [{
"name": "small",
"code": "s"
}, {
"name": "medium",
"code": "m"
}, {
"name": "large",
"code": "l"
}, {
"name": "extra large",
"code": "xl"
}]
},
"p_quantity": 1,
"p_originalprice": 22.0,
"p_price": 22.0,
"c_currency": "$"
}]
}
app.factory('CartService', function($http) {
var getProducts = function () {
return $http.get('products.json');
};
return {
$getProductsInCart : getProducts
};
});
Responsive Shopping cart module using AngularJS 1.5.x
=============
how it works
----------------
+ Entire shopping cart is designed as responsive screen
+ Media queries have been incorporated to support small devices (max-width : 480px) & desktop
+ Shopping cart contains logic for discount calculation based on promo-code provided
Demo
----------------
[demo @ plunker](http://plnkr.co/edit/TnffNy6WRp2UgY2ixgrc?p=info)