In case of add book we will be adding a button in the books page.For displaying the add books page in the books page we will be making
use of the
selector tag of the add book component. We will be showing the
add books page only when we have the action parameter as add.
Also we will be specifying the book as selectedBook which will be passed as input to the add 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">Show Details</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<app-addbook *ngIf="action === 'add'" [book]="selectedBook"></app-addbook>
</div>
</div>
Also we want to pass the new book that we have created to the child component i.e add book component.
We achieve this using the input tag.
Finally in the add-books component we create the Book named book and decorate it with the Input annotation.
This specifies that the book instance will be provided by the parent
component to the add user child component whenever it gets called.
import { Component, OnInit,Input } from '@angular/core';
import { Book } from '../../../model/Book';
@Component({
selector: 'app-addbook',
templateUrl: './addbook.component.html',
styleUrls: ['./addbook.component.css']
})
export class AddbookComponent implements OnInit {
@Input()
book: Book;
constructor() { }
ngOnInit() {
}
}
Let us now start the application and goto the books page.
Here we can see the list as follows-

Click on the Add button. We can see that the url has changed with the parameter action=add and also the
add book page can now be seen.
Next we will be modifying the Add Book Component to take book details and call the spring boot Back end
to save the new book. We will be making use of the ngModel directive to bind the form elements to Book object recieved from the
parent Books Component.
<h1>Add Book Admin</h1>
<form>
<label for="name">Name</label>
<input type="text" class="form-control" id="name" placeholder="Book Name" [(ngModel)]="book.name" name="name">
<label for="author">Author</label>
<input type="text" class="form-control" id="author" placeholder="author" name="author" [(ngModel)]="book.author">
<label for="author">Price</label>
<input type="text" class="form-control" id="price" placeholder="price" name="price" [(ngModel)]="book.price">
<br>
<input type="file" (change)="onFileChanged($event)">
<img [src]="imgURL" height="200" width="200" *ngIf="imgURL">
<br>
<button type="button" class="btn btn-success" (click)="saveBook()">Save Book</button>
</form>
Next in the HttpClientService we will be adding the addBook method. This method will be making a POST call to Spring backend
to save the book.
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');
}
addBook(newBook: Book) {
return this.httpClient.post<Book>('http://localhost:8080/books/add', newBook);
}
}
Next we will be modifying the add user component typescript file -
- In the constructor add the HttpClientService and the Router
- Define the saveBook function to add new book
We will first be saving the image. If the image has been successfully saved we will then be saving the other book details.
In another
tutorial we had created an application for
saving an image using Angular8 UI.
import { Component, OnInit, Input } from '@angular/core';
import { Book } from '../../../model/Book';
import { HttpClientService } from '../../../service/http-client.service';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-addbook',
templateUrl: './addbook.component.html',
styleUrls: ['./addbook.component.css']
})
export class AddbookComponent implements OnInit {
@Input()
book: Book;
private selectedFile;
imgURL: any;
constructor(private httpClientService: HttpClientService,
private activedRoute: ActivatedRoute,
private router: Router,
private httpClient: HttpClient) { }
ngOnInit() {
}
public onFileChanged(event) {
console.log(event);
this.selectedFile = event.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = (event2) => {
this.imgURL = reader.result;
};
}
saveBook() {
const uploadData = new FormData();
uploadData.append('imageFile', this.selectedFile, this.selectedFile.name);
this.selectedFile.imageName = this.selectedFile.name;
this.httpClient.post('http://localhost:8080/books/upload', uploadData, { observe: 'response' })
.subscribe((response) => {
if (response.status === 200) {
this.httpClientService.addBook(this.book).subscribe(
(book) => {
this.router.navigate(['admin', 'books']);
}
);
console.log('Image uploaded successfully');
} else {
console.log('Image not uploaded successfully');
}
}
);
}
}
If we now run the application
Navigate to the add page -
enter the details and click on save

We can see that the list books is still not showing the added book.
If we refresh the books page then we can see the new book.

If we check the database we can see that new book has been added.

So we need to tell the parent books component that child add book component has added
a new Book so fetch the books list again.
We do this using the Output annotation.

In the add books component file add the Eventemitter. Also if the book is successfully
added then we send a signal to the parent books component.
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import { Book } from '../../../model/Book';
import { HttpClientService } from '../../../service/http-client.service';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-addbook',
templateUrl: './addbook.component.html',
styleUrls: ['./addbook.component.css']
})
export class AddbookComponent implements OnInit {
@Input()
book: Book;
@Output()
bookAddedEvent = new EventEmitter();
public selectedFile;
imgURL: any;
constructor(private httpClientService: HttpClientService,
private activedRoute: ActivatedRoute,
private router: Router,
private httpClient: HttpClient) { }
ngOnInit() {
}
public onFileChanged(event) {
console.log(event);
this.selectedFile = event.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = (event2) => {
this.imgURL = reader.result;
};
}
saveBook() {
const uploadData = new FormData();
uploadData.append('imageFile', this.selectedFile, this.selectedFile.name);
this.selectedFile.imageName = this.selectedFile.name;
this.httpClient.post('http://localhost:8080/books/upload', uploadData, { observe: 'response' })
.subscribe((response) => {
if (response.status === 200) {
this.httpClientService.addBook(this.book).subscribe(
(book) => {
this.bookAddedEvent.emit();
this.router.navigate(['admin', 'books']);
}
);
console.log('Image uploaded successfully');
} else {
console.log('Image not uploaded successfully');
}
}
);
}
}
In the books component we specify the function to be called on bookAddedEvent.
<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">Show Details</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<app-addbook *ngIf="action === 'add'" [book]="selectedBook" (bookAddedEvent)="refreshData()"></app-addbook>
</div>
</div>
Finally in the books component we define the refreshData function. This function will fetch the user list from the Spring Boot Application.
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>;
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) => {
this.action = params['action'];
}
);
}
handleSuccessfulResponse(response) {
this.books = response;
}
addBook() {
this.selectedBook = new Book();
this.router.navigate(['admin', 'books'], { queryParams: { action: 'add' } });
}
}
Now if we go to localhost:4200/admin/books and add a new book-

The new book gets immediately reflected in the users list.
Download Source Code
Download it -
Spring Boot + E-commerce
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