Setting up the shopping cart

One of the main advantages of developing on open source technology is that we don’t have to reinvent the wheel with every feature. We first look if there’s any module that already does what we want to accomplish, before we start it ourselves, from scratch. That’s true in the case of the shopping cart; we are going to use the already available module: ngCart.

Installing ngCart

The ngCart module provides the following directives and services that we need to get started with the shopping cart:

  1. It renders an Add to cart button: <ngcart-addtocart id="{{item.id}}" name="{{item.name}}" price="{{item.price}}"></ngcart-addtocart>.
  2. Renders a shopping cart: <ngcart-cart></ngcart-cart>.
  3. Shows the cart summary: <ngcart-summary></ngcart-summary>.
  4. Renders the checkout buttons for PayPal and other HTTP services: <ngcart-checkout service="http" settings="{url:'/checkout' }"></ngcart-checkout>.

We are going to use bower to quickly install ngCart in our project:

bower install ngcart#1.0.0 --save

There is no need to worry about adding it to index.html; a grunt task (grunt-wiredep) will inject it for us. Let’s go ahead and load it with the rest of our angularjs dependencies in app.js:

/* client/app/app.js *excerpt */ 

angular.module('meanshopApp', [
  'ngCookies',
  'ngResource',
  'ngSanitize',
  'btford.socket-io',
  'ui.router',
  'ui.bootstrap',
  'ngFileUpload',
  'ngCart'
])

The ngCart directives require some templates for its directives. We need to copy them to our project:

cp -R client/bower_components/ngcart/template/ngCart client/components/ngcart

Every time we use any of the aforementioned directives, they are going to be translated to their matching template:

  • client/components/ngcart/addtocart.html
  • client/components/ngcart/cart.html
  • client/components/ngcart/checkout.html
  • client/components/ngcart/summary.html

So every time we want to customize the look and feel, this is the place to go.

Making use of ngCart directives

We are going to make use of four directives/templates in our project, and create a new checkout page that shows the shopping cart and adds the checkout strategies.

Add/remove to cart

First, let’s replace the Buy button for the Add to cart button in the products listing page (product-list.html line 14). Replace the following code:

<a href="#" class="btn btn-primary" role="button">Buy</a>

With the following code:

<!-- client/app/products/templates/product-list.html:14 -->

<ngcart-addtocart id="{{product._id}}" quantity="1" quantity-max="9" name="{{product.title}}" price="{{product.price}}" template-url="components/ngcart/addtocart.html" data="product">Add to Cart</ngcart-addtocart>

Do the same in product-view.html; replace the buy button for the ngcart-addtocart directive. Now, let’s change the default template:

<!-- client/components/ngcart/addtocart.html -->

<span ng-hide="attrs.id">
  <a class="btn btn-primary" ng-disabled="true" ng-transclude></a>
</span>
<span ng-show="attrs.id">
  <span ng-show="!inCart()">
    <span ng-show="quantityMax">
      <select name="quantity" id="quantity" ng-model="q" ng-options=" v for v in qtyOpt"></select>
    </span>
    <a class="btn btn-primary" ng-click="ngCart.addItem(id, name, price, q, data)" ng-transclude></a>
  </span>
  <mark  ng-show="inCart()">
    <a class="btn btn-success" ng-click="ngCart.removeItemById(id)">Added</a>
  </mark>
</span>

With this new template, we only need one button. If you click once, we add the items to the cart, and if we click again, we remove it from the cart. Pretty simple! Moreover, we have a dropdown menu to select the number of items we want at a time.

The cart’s summary

Next, let’s add a summary of the checkout cart in navbar.html, just before line 26:

<!-- client/components/navbar/navbar.html:26 | excerpt -->

<li>
  <a ui-sref="checkout">
    <ngcart-summary template-url="components/ngcart/summary.html"></ngcart-summary>
  </a>
</li>

Notice that we are linking the cart summary to the checkout state. Let’s create that state:

/* client/app/products/products.js:30 */

.state('checkout', {
  url: '/checkout',
  templateUrl: 'app/products/templates/products-checkout.html',
  controller: 'ProductCheckoutCtrl'
});

The next step is to adjust the summary.html template for a better look and feel. Replace the whole content of the template for these few lines:

/* client/components/ngcart/summary.html */

<span class="fa fa-shopping-cart"></span>
{{ ngCart.getTotalItems() }} /
{{ ngCart.totalCost() | currency }}

Save