Search Tutorials


Ecommerce Website - Online Book Store - Create Book Admin Module - Part 3 | JavaInUse
     
 

   
   

Ecommerce Website - Online Book Store - Create User Admin Module - Part 3

In this tutorial series we will be developing an ecommerce website for buying books. In a previous tutorial we created the books admin module to to add new book. In this tutorial we will be creating the view book module using which we can view existing book details. Also we can delete an existing book.

Ecommerce Website - Online Book Store using Angular 8 + Spring Boot

Ecommerce Website - Online Book Store using Angular 8 + Spring Boot Introduction Ecommerce Website - Online Book Store - Create Menu Module Ecommerce Website - Online Book Store - Create User Admin Module - Part 1 Ecommerce Website - Online Book Store - Create User Admin Module - Part 2 Ecommerce Website - Online Book Store - Create User Admin Module - Part 3 Ecommerce Website - Online Book Store - Create Book Admin Module - Part 1 Ecommerce Website - Online Book Store - Create Book Admin Module - Part 2 Ecommerce Website - Online Book Store - Create Book Admin Module - Part 3 Ecommerce Website - Online Book Store - Create Book Admin Module - Part 4 Ecommerce Website - Online Book Store - Create Book Shopping Module

Video

This tutorial is explained in the below Youtube Video.

Spring Boot Application

We will be modifying the Spring Boot Application we had created in the previous tutorial. In the controller class add a method for deleting the existing book.
package com.javainuse.controller;

import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.javainuse.db.BookRepository;
import com.javainuse.model.Book;

@RestController
@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping(path = "books")
public class BookController {

	private byte[] bytes;

	@Autowired
	private BookRepository bookRepository;

	@GetMapping("/get")
	public List<Book> getBooks() {
		return bookRepository.findAll();
	}

	@PostMapping("/upload")
	public void uploadImage(@RequestParam("imageFile") MultipartFile file) throws IOException {
		this.bytes = file.getBytes();
	}

	@PostMapping("/add")
	public void createBook(@RequestBody Book book) throws IOException {
		book.setPicByte(this.bytes);
		bookRepository.save(book);
		this.bytes = null;
	}

	@PutMapping("/update")
	public void updateBook(@RequestBody Book book) {
		bookRepository.save(book);
	}

	@DeleteMapping(path = { "/{id}" })
	public Book deleteBook(@PathVariable("id") long id) {
		Book book = bookRepository.getOne(id);
		bookRepository.deleteById(id);
		return book;
	}

}

Angular Code

We will be modifying the angular code we had implemented in previous tutorial. The page Structure for the Book-Admin Page is as follows-

The Books Component will be having two child components - Add Book Component and View Book Component.

In this tutorial we will be implementing the view/delete book component. Create a new component named view book.
ng generate component admin/books/viewbook


In previous tutorial for adding new book we had already created the domain class Book. We will be adding one more field to the Book class. This is needed to display the image using the image bytes received.
export class Book {
    id: number;
    name: string;
    author: string;
    price: number;
    picByte: string;
   retrievedImage: string;
}
 We have already added the show details button in the book component. On this click the view book component  should be called along with the book details displayed. So whenever we will load the books component we will also be checking the url component  
  •  if the url has action=add then the addbook page will be displayed.  
  • If the url has the  action=view then the view book page will be displayed.  
  • if no action parameter is present  then neither the add book page or the view book page will be displayed.  
  In Books component, we will be  
  •   In the constructor add the activatedRoute and router.  
    •  ActivatedRoute - Gives us access to the current route instance.
    •  Router - using this we can navigate to another page.
     
  • In the ngOnInit function  we will be  using the ActivatedRoute to check id the url contains any id. If it contains the id it means we have to  show the view page for the selected book.  
  •  Implement the viewBook function. In this function using the Router we will be  again navigating to the same page - /admin/books,  but with additional parameters of action=view and the id of the selected book.  
  • Also we will be modifying the book list that we have received from the backend. We add the value of retrievedImage to display the image.
  •  
import { Component, OnInit } from '@angular/core';
import { Book } from '../../model/Book';
import { HttpClientService } from '../../service/http-client.service';
import { ActivatedRoute, Router } from '@angular/router';

@Component({
  selector: 'app-books',
  templateUrl: './books.component.html',
  styleUrls: ['./books.component.css']
})
export class BooksComponent implements OnInit {

  books: Array<Book>;
  booksRecieved: Array<Book>;
  selectedBook: Book;
  action: string;

  constructor(private httpClientService: HttpClientService,
    private activedRoute: ActivatedRoute,
    private router: Router) { }

  ngOnInit() {
    this.refreshData();
  }

  refreshData() {
    this.httpClientService.getBooks().subscribe(
      response => this.handleSuccessfulResponse(response)
    );
    this.activedRoute.queryParams.subscribe(
      (params) => {
        // get the url parameter named action. this can either be add or view.
        this.action = params['action'];
	// get the parameter id. this will be the id of the book whose details 
	// are to be displayed when action is view.
	const id = params['id'];
	// if id exists, convert it to integer and then retrive the book from
	// the books array
        if (id) {
          this.selectedBook = this.books.find(book => {
            return book.id === +id;
          });
        }
      }
    );
  }

  // we will be taking the books response returned from the database
  // and we will be adding the retrieved   
  handleSuccessfulResponse(response) {
    this.books = new Array<Book>();
    //get books returned by the api call
    this.booksRecieved = response;
    for (const book of this.booksRecieved) {
    
      const bookwithRetrievedImageField = new Book();
      bookwithRetrievedImageField.id = book.id;
      bookwithRetrievedImageField.name = book.name;
      //populate retrieved image field so that book image can be displayed
      bookwithRetrievedImageField.retrievedImage = 'data:image/jpeg;base64,' + book.picByte;
      bookwithRetrievedImageField.author = book.author;
      bookwithRetrievedImageField.price = book.price;
      bookwithRetrievedImageField.picByte=book.picByte;
      this.books.push(bookwithRetrievedImageField);
    }
  }

  addBook() {
    this.selectedBook = new Book();
    this.router.navigate(['admin', 'books'], { queryParams: { action: 'add' } });
  }

  viewBook(id: number) {
    this.router.navigate(['admin', 'books'], { queryParams: { id, action: 'view' } });
  }
}
For displaying the viewbook page in the books page we will be making use of the selector tag of the view book component. We will be showing the view books page only when we have the action parameter as view.  Also we will be specifying the book as selectedBook which will be passed as input to the view book component.
<h1>Books Admin</h1>
<a class="btn btn-primary mb-3" (click)="addBook()">Add New Book</a>
<div class="container row">
  <div class="col-md-6">
    <table class="table">
      <thead>
        <tr>
          <th>ID</th>
          <th>Book Name</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let book of books">
          <td>{{book.id}}</td>
          <td>{{book.name}}</td>
          <td>
            <button type="button" class="btn btn-primary" (click)="viewBook(book.id)"> Show Details</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="col-md-6">
    <app-addbook *ngIf="action === 'add'" [book]="selectedBook" (bookAddedEvent)="loadData()"></app-addbook>
    <app-viewbook *ngIf="action === 'view'" [book]="selectedBook"></app-viewbook>
  </div>
</div>
Also we want to pass the new book that we have created to the child component i.e view book component.  We acheive this using the input tag.    

Finally in the view-books component we create the Book named user and decorate it with the Input annotation. This specifies that the book instance will be provided by the parent component to the view book child component whenever it gets called.
import { Component, OnInit, Input } from '@angular/core';
import { Book } from '../../../model/Book';

@Component({
  selector: 'app-viewbook',
  templateUrl: './viewbook.component.html',
  styleUrls: ['./viewbook.component.css']
})
export class ViewbookComponent implements OnInit {

  @Input()
  book: Book;

  constructor() { }

  ngOnInit() {
  }

}
Let us now start the application and goto the books page. Click on the Show Details button. We can see that the url has changed with the parameter action=view and the selectedId. Also the view book page can now be seen.

Next we will be modifying the View Book Component to take book details and show the book details. Also we will be showing the delete button using which the book will get deleted.
    <h1>Book Details</h1>

    <table>
        <tr>
            <td>Book Id</td>
            <td>{{book.id}}</td>
        </tr>
        <tr>
            <td>Book Name</td>
            <td>{{book.name}}</td>
        </tr>
        <tr>
            <td>Book Author</td>
            <td>{{book.author}}</td>
        </tr>
        <tr>
            <td>Book Price</td>
            <td>{{book.price}}</td>
        </tr>
    </table>
    <br>
    <img src="{{book.retrievedImage}}" height="200" width="200">
    <br><br>

    <a class="btn btn-small btn-danger" (click)="deleteBook()">delete</a>
Also in the view component css page we need to specify css for the table we use to display book details.
table, th, td {
    padding: 10px;
	border: 1px solid black;
	border-collapse: collapse;
}
Next in the HttpClientService we will be adding the deleteUser method. This method will be making a DELETE call to Spring backend to delete the user.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { User } from '../model/User';
import { Book } from '../model/Book';


@Injectable({
  providedIn: 'root'
})
export class HttpClientService {

  constructor(private httpClient: HttpClient) {
  }

  getUsers() {
    return this.httpClient.get<User[]>('http://localhost:8080/users/get');
  }

  addUser(newUser: User) {
    return this.httpClient.post<User>('http://localhost:8080/users/add', newUser);
  }

  deleteUser(id) {
    return this.httpClient.delete<User>('http://localhost:8080/users/' + id);
  }

  getBooks() {
    return this.httpClient.get<Book[]>('http://localhost:8080/books/get');
  }

  addUploadData(selectedFile) {
    return this.httpClient.post('http://localhost:8080/books/upload', selectedFile);
  }

  addBook(newBook) {
    return this.httpClient.post<Book>('http://localhost:8080/books/add', newBook);
  }

  deleteBook(id) {
    return this.httpClient.delete<Book>('http://localhost:8080/books/' + id);
  }
}
Next we will be modifying the view book component typescript file -
  • In the constructor add the HttpClientService and the Router
  • Define the deleteUser function to delete selected book
import { Component, OnInit, Input } from '@angular/core';
import { Book } from '../../../model/Book';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClientService } from '../../../service/http-client.service';

@Component({
  selector: 'app-viewbook',
  templateUrl: './viewbook.component.html',
  styleUrls: ['./viewbook.component.css']
})
export class ViewbookComponent implements OnInit {

  @Input()
  book: Book;

  constructor(private httpClientService: HttpClientService, private router: Router
  ) { }

  ngOnInit() {
  }

  deleteBook() {
    this.httpClientService.deleteBook(this.book.id).subscribe(
      (book) => {
        this.router.navigate(['admin', 'books']);
      }
    );
  }

}
If we now run the application Navigate to the view user page and select the user-

If for any user, we click on delete user button the user will get deleted

We can see that the list users is still showing the deleted book.
If we refresh the users page then we can see book is deleted.

If we check the database we can see that book has been deleted.
So we need to tell the parent books component that child view book component has deleted an existing book so fetch the books list again. We do this using the Output annotation.

In the view books component file add the Eventemitter. Also if the user is successfully deleted then we send a signal to the parent books component.
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Book } from '../../../model/Book';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClientService } from '../../../service/http-client.service';

@Component({
  selector: 'app-viewbook',
  templateUrl: './viewbook.component.html',
  styleUrls: ['./viewbook.component.css']
})
export class ViewbookComponent implements OnInit {

  @Input()
  book: Book;
  @Output()
  bookDeletedEvent = new EventEmitter();

  constructor(private httpClientService: HttpClientService, private router: Router
  ) { }

  ngOnInit() {
  }

  deleteBook() {
    this.httpClientService.deleteBook(this.book.id).subscribe(
      (book) => {
        this.bookDeletedEvent.emit();
        this.router.navigate(['admin', 'books']);
      }
    );
  }

}
In the books component we specify the function to be called on bookDeletedEvent. We have already defined the refreshData function which we will be calling.
<h1>Books Admin</h1>
<a class="btn btn-primary mb-3" (click)="addBook()">Add New Book</a>
<div class="container row">
  <div class="col-md-6">
    <table class="table">
      <thead>
        <tr>
          <th>ID</th>
          <th>Book Name</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let book of books">
          <td>{{book.id}}</td>
          <td>{{book.name}}</td>
          <td>
            <button type="button" class="btn btn-primary" (click)="viewBook(book.id)"> Show Details</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="col-md-6">
    <app-addbook *ngIf="action === 'add'" [book]="selectedBook" (bookAddedEvent)="refreshData()"></app-addbook>
    <app-viewbook *ngIf="action === 'view'" [book]="selectedBook" (bookDeletedEvent)="refreshData()"></app-viewbook>
  </div>
</div>
Also we will be specifying the css for table to better display book details. So for view book component add the css-
table, th, td {
    padding: 10px;
    border: 1px solid black; 
    border-collapse: collapse;
    }
Now if we go to localhost:4200/admin/books and select an existing book-

On clicking Delete button the existing book gets immediately deleted in the books list.

Download Source Code

Download it -
Spring Boot + Ecommerce
Angular8 Online Book Store

 

See Also

Spring Boot Hello World Application- Create simple controller and jsp view using Maven Spring Boot Tutorial-Spring Data JPA Spring Boot + Simple Security Configuration Pagination using Spring Boot Simple Example Spring Boot + ActiveMQ Hello world Example Spring Boot + Swagger Example Hello World Example Spring Boot + Swagger- Understanding the various Swagger Annotations Spring Boot Main Menu Spring Boot Interview Questions