Build a shopping cart in Nodejs and Angular10

In this article we are going to build shopping cart frontend with Angular 10 for our application.

You can check our backend part built in Nodejs, which we already have published.

Note that you need to have the angular CLI installed on your local machine. To upgrade to Angular 10 you can follow up this tutorial.

To start up we need to setup our application directory. Create an angular-cart directory in your desktop and run this command to setup a new angular project:

cd desktop
mkdir angular-cart && cd angular-cart
ng new angular-cart

Running the ng new command will prompt some questions for the project scaffolding. Type y to add Angular routing to that project and select css as the default stylesheet.

Selecting this two things will create a new Angular 10 project. You can move into the project directory and then use the code . command to open up our project in VS Code.

To serve our application we can run ng serve which will open up our application on port 4200.

We will continue by setting up our user interface for the application. You can get all our UI components from WrapPixel's UI Kit.

WrapPixel is an online template store where you could get great Angular Dashboard Template and Angular Material Themes.

We will create our components for listing of products and cart details. We will also define a navbar component for page navigation.

To create a component run this on your terminal:

ng g c components/cart
ng g c components/navbar
ng g c components/products

This will create a components directory and create a cart modules where we will define our markup and styles.

We need to configure Bootstrap into our application by adding the CDN into the src/dex.html file.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularCart</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

Let’s define our navbar by editing the codes in the components/navbar/navbar.components.html to this:

 <nav class="navbar navbar-expand-lg navbar-light bg-info">
   <div class="container">
     <a routerLink="/" class="navbar-brand">Angular Cart</a>
     <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
       aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
       <span class="navbar-toggler-icon"></span>
     </button>
     <div class="collapse navbar-collapse justify-content-end" id="navbarNav">
       <ul class="navbar-nav">
         <li class="nav-item active">
           <a routerLink="/" class="nav-link">Home </a>
         </li>
         <li class="nav-item">
           <a routerLink="/cart" class="nav-link">Cart </a>
         </li>
       </ul>
     </div>
   </div>
 </nav>

And then modify the codes in the app/app.components.html to this:

<app-navbar></app-navbar>
<section>
  <div class="banner-innerpage" style="
          background-image: url(https://images.pexels.com/photos/1005638/pexels-photo-1005638.jpeg?cs=srgb&dl=pexels-oleg-magni-1005638.jpg&fm=jpg);
        ">
    <div class="container">
      <!-- Row  -->
      <div class="row justify-content-center">
        <!-- Column -->
        <div class="col-md-6 align-self-center text-center" data-aos="fade-down" data-aos-duration="1200">
          <h1 class="title">Shop listing</h1>
          <h6 class="subtitle op-8">
            We are small team of creative people working together.
          </h6>
        </div>
        <!-- Column -->
      </div>
    </div>
  </div>
</section>
<router-outlet></router-outlet>

We will add some styles in the app.component.css :

.banner-innerpage {
  padding: 150px 0 100px;
  background-size: cover;
  background-position: center center;
}
.banner-innerpage .title {
  color: #ffffff;
  text-transform: uppercase;
  font-weight: 700;
  font-size: 40px;
  line-height: 40px;
}
.banner-innerpage .subtitle {
  color: #ffffff;
}
.shop-listing .shop-hover {
  position: relative;
}
.shop-listing .shop-hover .card-img-overlay {
  display: none;
  background: rgba(255, 255, 255, 0.5);
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
}
.shop-listing .shop-hover:hover .card-img-overlay {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}
.shop-listing .shop-hover .label {
  padding: 5px 10px;
  position: absolute;
  top: 10px;
  right: 10px;
}
/*******************
shop table
*******************/
.shop-table td {
  padding: 30px 0;
}

Shop Header

Let’s register our routes in the app/app-routing.module.ts file :

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CartComponent } from './components/cart/cart.component';
import { ProductsComponent } from './components/products/products.component';
const routes: Routes = [
  { path: '', component: ProductsComponent },
  { path: 'cart', component: CartComponent },
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

With this done we can now handle routing in our navbar component by define the router links:

 <nav class="navbar navbar-expand-lg navbar-light bg-info">
   <div class="container">
     <a routerLink="/" class="navbar-brand">Angular Cart</a>
     <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
       aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
       <span class="navbar-toggler-icon"></span>
     </button>
     <div class="collapse navbar-collapse justify-content-end" id="navbarNav">
       <ul class="navbar-nav">
         <li class="nav-item active">
           <a routerLink="/" class="nav-link">Home </a>
         </li>
         <li class="nav-item">
           <a routerLink="/cart" class="nav-link">Cart </a>
         </li>
       </ul>
     </div>
   </div>
 </nav>

We can now create some services that will handle our HTTP requests. To create a service in Angular, open up your terminal and type the following:

ng g s http

This will create a http.service.ts file. We will bring in the Angular HttpClient for making http request and then define our http services:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
@Injectable({
  providedIn: 'root',
})
export class HttpService {
  constructor(private http: HttpClient) {}
  getAllProducts() {
    return this.http.get(`${environment.baseURL}/product`);
  }
  addToCart(payload) {
    return this.http.post(`${environment.baseURL}/cart`, payload);
  }
  getCartItems() {
    return this.http.get(`${environment.baseURL}/cart`);
  }
  increaseQty(payload) {
    return this.http.post(`${environment.baseURL}/cart`, payload);
  }
  emptyCart() {
    return this.http.delete(`${environment.baseURL}/cart/empty-cart`);
  }
}

We store our server baseURL in the environment.ts file:

baseURL: 'http://localhost:4000'

We can now use this services in our component. We will start from the products component, where we will be implementing listing of products and adding of product items to cart.

To be able to use the Angular httpClient module we have to register it globally in our application by importing it into our app/app.module.ts file:

import { HttpClientModule } from '@angular/common/http';
imports: [... other modules,HttpClientModule]

Let’s modify our codes in app/components/products.component.ts file to this:

import { Component, OnInit } from '@angular/core';
import { HttpService } from '../../http.service';
@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css'],
})
export class ProductsComponent implements OnInit {
  products: Array<object> = [];
  constructor(private http: HttpService) {}
  _getProducts(): void {
    this.http.getAllProducts().subscribe((data: any) => {
      this.products = data.data;
      console.log(this.products);
    });
  }
  _addItemToCart( id, quantity): void {
    let payload = {
      productId: id,
      quantity,
    };
    this.http.addToCart(payload).subscribe(() => {
      this._getProducts();
      alert('Product Added');
    });
  }
  ngOnInit(): void {
    this._getProducts();
  }
}

And then setup our template for the application by editing the products.component.ts file to this:

      <section>
        <div class="spacer">
          <div class="container">
            <div class="row mt-5">
              <div class="col-lg-9">
                <div class="row shop-listing">
                  <div class="col-lg-4" *ngFor="let product of products">
                    <div class="card shop-hover border-0">
                      <img [src]="'http://localhost:5000/' + product.image" alt="wrapkit" class="img-fluid" />
                      <div class="card-img-overlay align-items-center">
                        <button class="btn btn-md btn-info" (click)="_addItemToCart(product._id, 1)">Add to Cart</button>
                      </div>
                    </div>
                    <div class="card border-0">
                      <h6>
                        <a href="#" class="link">{{ product.name }}</a>
                      </h6>
                      <h6 class="subtitle">by Wisdom</h6>
                      <h5 class="font-medium m-b-30">
                        ${{product.price}}
                      </h5>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>

With this we can now list all our products and also add product items to cart.

We will proceed by implementing the cart section. Let’s define all our cart methods in the app/components/cart.component.ts file:

import { Component, OnInit } from '@angular/core';
import { HttpService } from '../../http.service';
@Component({
  selector: 'app-cart',
  templateUrl: './cart.component.html',
  styleUrls: ['./cart.component.css'],
})
export class CartComponent implements OnInit {
  carts;
  cartDetails;
  constructor(private http: HttpService) {}
  _getCart(): void {
    this.http.getCartItems().subscribe((data: any) => {
      this.carts = data.data;
      // this.cartDetails = data.data;
      console.log(this.carts);
    });
  }
  _increamentQTY(id, quantity): void {
    const payload = {
      productId: id,
      quantity,
    };
    this.http.increaseQty(payload).subscribe(() => {
      this._getCart();
      alert('Product Added');
    });
  }
  _emptyCart(): void {
    this.http.emptyCart().subscribe(() => {
      this._getCart();
      alert('Cart Emptied');
    });
  }
  ngOnInit(): void {
    this._getCart();
  }
}

And also setup a template for listing the cart items in the html file:

      <section>
        <div class="spacer">
          <div class="container">
            <div class="row mt-5">
              <div class="col-lg-9">
                <div class="row shop-listing">
                  <table class="table shop-table" *ngIf="carts">
                    <tr>
                      <th class="b-0">Name</th>
                      <th class="b-0">Price</th>
                      <th class="b-0">Quantity</th>
                      <th class="b-0 text-right">Total Price</th>
                    </tr>
                    <tr *ngFor="let item of carts.items">
                      <td>{{ item.productId.name }}</td>
                      <td>{{ item.productId.price }}</td>
                      <td>
                        <button class="btn btn-primary btn-sm" (click)="_increamentQTY(item.productId._id,1)">+</button>
                        {{ item.quantity }}
                        <button class="btn btn-primary btn-sm">-</button>
                      </td>
                      <td class="text-right">
                        <h5 class="font-medium m-b-30">{{ item.total }}</h5>
                      </td>
                    </tr>
                    <tr>
                      <td colspan="3" align="right">Subtotal :{{ carts.subTotal }}</td>
                      <td colspan="4" align="right">
                        <button class="btn btn-danger" (click)="_emptyCart()">Empty Cart</button>
                      </td>
                    </tr>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>

Shopping Cart

Exercise

  • Implement the decrement feature
  • Implement remove product from cart

After implementing this, Push your work to git and add the link in the comment section. Lets have some fun😁

Learn Something New Everyday,
Connect With The Best Developers!

Sign Up Now!

& 500k+ others use Hashnode actively.

No Comments Yet