Home Angular Building static food ordering application in Angular 19 with Bootstrap 5

Building static food ordering application in Angular 19 with Bootstrap 5

by therichpost
0 comments
Building static food ordering application in Angular 19 with Bootstrap 5

Hello guys how are you? Welcome back on my blog Therichpost. Today in this post I am going to share Building static food ordering application in Angular 19 with Bootstrap 5.

Live Demo

Angular 19 came. If you are new then you must check below two links:

Now guys here is the complete code snippet and please follow carefully:

Here’s a structured plan to build a static food ordering application in Angular 19 with Bootstrap 5. This includes the features you want: a good header and footer, a cart, checkout functionality, and a single item page.


Project Setup

  1. Create a New Angular Project
   ng new food-ordering-app
   cd food-ordering-app

Choose the routing option and select SCSS as the stylesheet format.

  1. Install Bootstrap 5
    Add Bootstrap to your Angular project:
   npm install bootstrap

Update the angular.json file to include Bootstrap styles:

   "styles": [
       "node_modules/bootstrap/dist/css/bootstrap.min.css",
       "src/styles.scss"
   ]
  1. Add FontAwesome (Optional)
    For icons, install FontAwesome:
   npm install @fortawesome/fontawesome-free

Include it in angular.json as well.


Application Structure

  • Header Component: Contains navigation links.
  • Footer Component: Displays footer content.
  • Home Component: Displays a list of food items.
  • Single Item Page: Detailed view of a food item.
  • Cart Component: Displays items in the cart.
  • Checkout Component: Form to input customer details and finalize the order.

Components and Routing

Generate the necessary components:

ng generate component components/header
ng generate component components/footer
ng generate component pages/home
ng generate component pages/single-item
ng generate component pages/cart
ng generate component pages/checkout

Configure routes in app-routs.ts:

import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { SingleItemComponent } from './pages/single-item/single-item.component';
import { CartComponent } from './pages/cart/cart.component';
import { CheckoutComponent } from './pages/checkout/checkout.component';

export const routes: Routes = [
    { path: '', component: HomeComponent },
    { path: 'item/:id', component: SingleItemComponent },
    { path: 'cart', component: CartComponent },
    { path: 'checkout', component: CheckoutComponent },
];

Component Details

Header Component

Include navigation links and a cart icon:

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" routerLink="/">Food Ordering</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a class="nav-link" routerLink="/">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" routerLink="/cart">Cart</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

Footer Component

Create a sticky footer with copyright info:

<footer class="bg-dark text-white text-center py-3">
  © 2025 Food Ordering App. All rights reserved.
</footer>

Home Component

Display a grid of food items:

<div class="container mt-4">
    <div class="row">
      <div class="col-md-4" *ngFor="let item of foodItems">
        <div class="card">
          <img src="{{ item.image }}" class="card-img-top img-fluid"  style="height: 250px; object-fit: cover;" alt="{{ item.name }}">
          <div class="card-body">
            <h5 class="card-title">{{ item.name }}</h5>
            <p class="card-text">{{ item.description }}</p>
            <p class="card-text text-primary">${{ item.price }}</p>
            <a [routerLink]="['/item', item.id]" class="btn btn-primary">View Details</a>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="container mt-5 mb-5">
    <h2>Special Offers</h2>
    <div class="row">
      <div class="col-md-4">
        <div class="card bg-warning text-white">
          <img src="assets/images/pasta.jpg" class="card-img-top" style="height: 250px; object-fit: cover;" alt="Special Offer">
          <div class="card-body">
            <h5 class="card-title">Buy 1 Get 1 Free Pizza</h5>
            <p class="card-text">Order any large pizza and get another one for free! Limited time only.</p>
          </div>
        </div>
      </div>
      <div class="col-md-4">
        <div class="card bg-danger text-white">
          <img src="assets/images/pizza.jpg" class="card-img-top" style="height: 250px; object-fit: cover;" alt="Special Offer">
          <div class="card-body">
            <h5 class="card-title">10% Off on Your First Order</h5>
            <p class="card-text">Enjoy 10% off your first order with us. Use code FIRST10.</p>
          </div>
        </div>
      </div>
      <div class="col-md-4">
        <div class="card bg-success text-white">
          <img src="assets/images/burger.jpg" class="card-img-top" style="height: 250px; object-fit: cover;" alt="Special Offer">
          <div class="card-body">
            <h5 class="card-title">Free Drink with Every Burger</h5>
            <p class="card-text">Get a free soft drink with every burger ordered. Don't miss out!</p>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="container mt-5 py-5 newsletter-section bg-light rounded-3 shadow">
    <div class="row align-items-center">
      <!-- Left Content: Text and Details -->
      <div class="col-md-6 text-center text-md-start">
        <h2 class="fw-bold">Stay Updated!</h2>
        <p class="text-muted">Subscribe to our newsletter and get exclusive offers, updates, and mouth-watering recipes delivered straight to your inbox.</p>
      </div>
      <!-- Right Content: Subscription Form -->
      <div class="col-md-6">
        <form class="d-flex">
          <input type="email" class="form-control me-2 rounded-pill shadow-sm" placeholder="Enter your email" aria-label="Enter your email" required>
          <button class="btn btn-primary px-4 rounded-pill shadow-sm" type="submit">Subscribe</button>
        </form>
        <!-- Optional Privacy Text -->
        <small class="d-block mt-2 text-muted">We respect your privacy. Unsubscribe anytime.</small>
      </div>
    </div>
  </div>
  
  

Single Item Component

Show detailed info and add to cart:

<div class="container mt-4">
    <h2>{{ item.name }}</h2>
    <img [src]="item.image" class="card-img-top img-fluid"  style="height: 350px; object-fit: cover;"  alt="{{ item.name }}">
    <p>{{ item.description }}</p>
    <p class="text-primary">Price: ${{ item.price }}</p>
    <button class="btn btn-success" (click)="addToCart()">Add to Cart</button>
  </div>
  

Cart Component

Display selected items:

<div class="container mt-4">
    <h2>Your Cart</h2>
    <div *ngIf="cartItems.length === 0">Your cart is empty!</div>
    <table class="table" *ngIf="cartItems.length > 0">
      <thead>
        <tr>
          <th>Item</th>
          <th>Price</th>
          <th>Quantity</th>
          <th>Total</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let item of cartItems">
          <td>{{ item.name }}</td>
          <td>${{ item.price }}</td>
          <td>{{ item.quantity }}</td>
          <td>${{ item.price * item.quantity }}</td>
        </tr>
      </tbody>
    </table>
    <a routerLink="/checkout" class="btn btn-primary">Proceed to Checkout</a>
  </div>
  

Checkout Component

Form for user details:

<div class="container mt-4">
    <h2>Checkout</h2>
    <form (ngSubmit)="placeOrder()">
      <div class="mb-3">
        <label for="name" class="form-label">Name</label>
        <input type="text" id="name" class="form-control" required>
      </div>
      <div class="mb-3">
        <label for="address" class="form-label">Address</label>
        <input type="text" id="address" class="form-control" required>
      </div>
      <div class="mb-3">
        <label for="card" class="form-label">Card Number</label>
        <input type="text" id="card" class="form-control" required>
      </div>
      <button type="submit" class="btn btn-success">Place Order</button>
    </form>
  </div>
  

Styling

Add global styles in src/styles.scss for consistency:

/* You can add global styles to this file, and also import other style files */
body {
    font-family: 'Arial', sans-serif;
  }
  footer {
    
    width: 100%;
  }
  /* Add to styles.scss */
.navbar {
  position: fixed;
  width: 100%;
  top: 0;
  z-index: 1000;
}

body {
  padding-top: 56px; /* Adjust this value to match navbar height */
}
.newsletter-section {
    background: linear-gradient(135deg, #f8f9fa, #e9ecef); /* Subtle gradient background */
    padding: 2rem 1rem;
  }
  
  .newsletter-section h2 {
    color: #343a40; /* Darker text for contrast */
  }
  
  .newsletter-section .form-control {
    border: 2px solid #dee2e6; /* Slight border for better visibility */
    transition: all 0.3s ease; /* Smooth interaction effect */
  }
  
  .newsletter-section .form-control:focus {
    border-color: #0d6efd; /* Highlight on focus */
    box-shadow: 0 0 10px rgba(13, 110, 253, 0.5); /* Glowing effect */
  }
  
  .newsletter-section .btn-primary {
    background: #0d6efd; /* Bootstrap primary color */
    border: none;
    transition: all 0.3s ease; /* Smooth hover effect */
  }
  
  .newsletter-section .btn-primary:hover {
    background: #084298; /* Darker blue on hover */
  }
  
  .newsletter-section small {
    font-size: 0.85rem;
  }
  

Mock Data

Populate it with sample data and methods for managing the cart.

Create a service to handle food items and cart operations:

Generate the Service

ng generate service services/food

Service Implementation (food.service.ts)

import { Injectable } from '@angular/core';

interface FoodItem {
  id: number;
  name: string;
  description: string;
  price: number;
  image: string;
  quantity?: number; // Optional for cart purposes
}

@Injectable({
  providedIn: 'root',
})
export class FoodService {
  private foodItems: FoodItem[] = [
    { id: 1, name: 'Pizza', description: 'Cheesy delight', price: 10, image: 'assets/images/pizza.jpg' },
    { id: 2, name: 'Burger', description: 'Juicy and tasty', price: 8, image: 'assets/images/burger.jpg' },
    { id: 3, name: 'Pasta', description: 'Italian classic', price: 12, image: 'assets/images/pasta.jpg' },
  ];

  private cart: FoodItem[] = [];

  getFoodItems(): FoodItem[] {
    return this.foodItems;
  }

  getFoodItemById(id: number): FoodItem | undefined {
    return this.foodItems.find(item => item.id === id);
  }

  getCartItems(): FoodItem[] {
    return this.cart;
  }

  addToCart(item: FoodItem): void {
    const cartItem = this.cart.find(cartItem => cartItem.id === item.id);
    if (cartItem) {
      cartItem.quantity! += 1;
    } else {
      this.cart.push({ ...item, quantity: 1 });
    }
  }

  clearCart(): void {
    this.cart = [];
  }
}

Food Item Display

Home Component (home.component.ts)

import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FoodService } from '../../services/food.service';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterLink, CommonModule],
  templateUrl: './home.component.html',
  styleUrl: './home.component.css'
})
export class HomeComponent {
  foodItems:any;

  constructor(private foodService: FoodService) {}

  ngOnInit(): void {
    this.foodItems = this.foodService.getFoodItems();
  }
}

Single Item Page

Component (single-item.component.ts)

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { FoodService } from '../../services/food.service';

@Component({
  selector: 'app-single-item',
  templateUrl: './single-item.component.html',
  styleUrls: ['./single-item.component.scss'],
})
export class SingleItemComponent implements OnInit {
  item: any;

  constructor(
    private route: ActivatedRoute,
    private foodService: FoodService
  ) {}

  ngOnInit(): void {
    const itemId = Number(this.route.snapshot.paramMap.get('id'));
    this.item = this.foodService.getFoodItemById(itemId);
  }

  addToCart(): void {
    this.foodService.addToCart(this.item);
    alert(`${this.item.name} added to cart!`);
  }
}

Cart Page

Component (cart.component.ts)

import { Component } from '@angular/core';
import { FoodService } from '../../services/food.service';
import { CommonModule } from '@angular/common';
import { RouterLink } from '@angular/router';

@Component({
  selector: 'app-cart',
  standalone: true,
  imports: [CommonModule, RouterLink],
  templateUrl: './cart.component.html',
  styleUrl: './cart.component.css'
})
export class CartComponent {
  cartItems:any;

  constructor(private foodService: FoodService) {}

  ngOnInit(): void {
    this.cartItems = this.foodService.getCartItems();
  }
}

Checkout Page

Component (checkout.component.ts)

import { Component } from '@angular/core';
import { FoodService } from '../../services/food.service';
import { CommonModule } from '@angular/common';
import { RouterLink } from '@angular/router';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [],
  templateUrl: './checkout.component.html',
  styleUrl: './checkout.component.css'
})
export class CheckoutComponent {
  constructor(private foodService: FoodService) {}

  placeOrder(): void {
    alert('Order placed successfully!');
    this.foodService.clearCart();
  }
}

This should now be a complete static food ordering app with Angular 19 and Bootstrap 5. If you’d like further refinements or additions, let me know and feel free to comment below!

Ajay

Thanks

You may also like

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.