Crud Customer Application Spring boot and Angular Part 2

Getting Started | Building an Application with Angular



Angular 10 Front-end

In this tutorial, we will learn how to build a full stack Angular 10 + Spring Boot example with a CRUD App. The back-end server uses Spring Boot with Spring Web MVC for REST Controller and Spring Data JPA for interacting with MySQL database. Front-end side is made with Angular 10, HTTPClient & Router.


Angular CLI version (10.1.1)

ng new

The Angular CLI makes it easy to create an application that already works, right out of the box. It already follows our best practices!


ng generate

Generate components, routes, services and pipes with a simple command. The CLI will also create simple test shells for all of these.


ng serve

Easily test your app locally while developing.



$  npm install -g @angular/cli
$ ng new crud-customer
$ cd crud-customer
$ ng serve

Technology

Angular 10

Angular HTTPClient

Angular Router


Project Structure


Install Bootstrap CSS framework

Use the following command to install bootstrap in the project.


$  npm install bootstrap --save

src/style.css


@import  '~bootstrap/dist/css/bootstrap.min.css';

Let's create a class by using the following command

Create the Customer.ts class


$  ng g class Customer

The purpose of this class is to map the specified fields with the fields of Spring entity class.


export class Customer { id: number; firstname: string; lastname: string; age: number; active: boolean; }

Create Data Service

This service will use Angular HTTPClient to send HTTP requests. You can see that its functions includes CRUD operations and finder method.

service customer.service.ts

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Customer } from '../model/Customer'; @Injectable({ providedIn: 'root' }) export class CustomerService { private baseUrl = 'http://localhost:8080/api/customers'; constructor(private http: HttpClient) { } getCustomer(id: number): Observable<Customer> { return this.http.get<Customer>(`${this.baseUrl}/${id}`); } createCustomer(customer: Customer): Observable<Customer> { return this.http.post<Customer>(`${this.baseUrl}` + `/create`, customer); } updateCustomer(id: number, value: Customer): Observable<Customer> { return this.http.put<Customer>(`${this.baseUrl}/update/${id}`, value); } deleteCustomer(id: number): Observable<any> { return this.http.delete(`${this.baseUrl}/delete/${id}`, { responseType: 'text' }); } getCustomersList(): Observable<any> { return this.http.get(`${this.baseUrl}/getAllCustomers`); } getCustomersByAge(age: number): Observable<any> { return this.http.get(`${this.baseUrl}/age/${age}`); } getCustomersById(id: number): Observable<any> { return this.http.get(`${this.baseUrl}/id/${id}`); } deleteAllCustomers(): Observable<any> { return this.http.delete(`${this.baseUrl}` + `/deleteAllCustomers`, { responseType: 'text' }); } isActive(id: number, value: Customer): Observable<Customer> { return this.http.put<Customer>(`${this.baseUrl}/isActive/${id}`, value); } inActive(id: number, value: Customer): Observable<Customer> { return this.http.put<Customer>(`${this.baseUrl}/inActive/${id}`, value); } }

Create Angular Components

As you’ve known before, there are 3 components corresponding to 3 routes defined in AppRoutingModule.


$  ng generate component add-customer
$ ng generate component customer-details
$ ng generate component customer-list
$ ng generate component edit-customer
$ ng generate component search-customer

Introduction to components and templates

A component controls a patch of screen called a view. For example, individual components define and control each of the following views from the Tour of application tutorial:


You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.

app.component.html


<div class="container app"> <h1 style="color: blue; text-align: center; margin: 30px 0 20px;">Spring boot and Angular Application Customer Curd</h1> <ul> <li> <a routerLink="customer" class="btn btn-primary active" role="button" routerLinkActive="active">Customers</a></li> <li> <a routerLink="add" class="btn btn-primary active" role="button" routerLinkActive="active">Add</a></li> <li> <a routerLink="findbyage" class="btn btn-primary active" role="button" routerLinkActive="active">Search</a></li> </ul> <router-outlet></router-outlet> </div>

app.component.css


.app ul { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #ddd; } .app li { float: left; border-right:1px solid #bbb; } .app li:last-child { border-right: none; } .app li a { display: block; color: white; text-align: center; padding: 14px 16px; text-decoration: none; }

Here, we are creating add-customer compoent

add-customer.html


<h2>Create Customer</h2> <div [hidden]="submitted" style="width: 300px;"> <form (ngSubmit)="save()" style="background: aliceblue; padding: 15px; border-radius: 10px;"> <div class="form-group"> <label>Firstname</label> <input type="text" class="form-control" id="firstname" required [(ngModel)]="customer.firstname" name="firstname"> </div> <div class="form-group"> <label>Lastname</label> <input type="text" class="form-control" id="lastname" required [(ngModel)]="customer.lastname" name="lastname"> </div> <div class="form-group"> <label>Age</label> <input type="text" class="form-control" id="age" required [(ngModel)]="customer.age" name="age"> </div> <button type="submit" class="btn btn-success"Submit</button> </form> </div> <div [hidden]="!submitted"> <h3>You submitted successfully</h3> <button class="btn btn-success" (click)="newCustomer()">Add</button> </div>

add-customer.ts


import { Component, OnInit } from '@angular/core'; import { Customer } from '../model/Customer'; import { CustomerService } from '../service/customer-service'; @Component({ selector: 'app-add-customer', templateUrl: './add-customer.component.html', styleUrls: ['./add-customer.component.css'] }) export class AddCustomerComponent implements OnInit { customer: Customer = new Customer(); submitted = false; constructor(private customerService: CustomerService) { } ngOnInit() {} save(){ this.customerService.createCustomer(this.customer).subscribe(customer => { this.customer = customer; this.submitted = true; }); this.customer = new Customer(); } newCustomer(): void { this.submitted = false; this.customer = new Customer(); } }

Here, we are creating customerdetails compoent

customer-details.html


<br><div class="card" style="width: 18rem;" *ngIf="customer"> <div class="card-header"> <h2>Customer</h2> </div> <ul class="list-group list-group-flush"> <li class="list-group-item">Firstname: {{customer.firstname}}</li> <li class="list-group-item">Lastname: {{customer.lastname}}</li> <li class="list-group-item">Age: {{customer.age}}</li> <li class="list-group-item list-group-item-danger" *ngIf="!customer.active">Active: {{customer.active}}</li> <li class="list-group-item list-group-item-success" *ngIf="customer.active">Active: {{customer.active}}</li> </ul> <div class="card-body"> <span class="badge bg-warning"lass="button is-small btn-primary" *ngIf="!customer.active" (click)="isActive()">Inactive</span> <span class="badge bg-success" *ngIf="customer.active" (click)="inActive()">Active</span> <span class="badge bg-info" (click)="update()">Update</span> <span class="badge bg-danger" (click)="deleteCustomer(customer.id)">Delete</span> </div> </div>

add-customer.css


.badge { cursor: pointer; margin-left: 10px; }

customer-details.component.ts


import { Component, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { CustomerListComponent } from '../customer-list/customer-list.component'; import { Customer } from '../model/Customer'; import { CustomerService } from '../service/customer-service'; @Component({ selector: 'app-customer-details', templateUrl: './customer-details.component.html', styleUrls: ['./customer-details.component.css'] }) export class CustomerDetailsComponent implements OnInit { @Input() customer: Customer = new Customer(); constructor(private customerService: CustomerService, private router: Router, private listCustomer: CustomerListComponent) { } ngOnInit() {} isActive(){ this.customerService.isActive(this.customer.id, this.customer).subscribe(customer => { this.customer = customer; this.listCustomer.reloadData(); }, error => console.log(error)); } inActive() { this.customerService.inActive(this.customer.id, this.customer).subscribe(customer => { this.customer = customer; this.listCustomer.reloadData(); }, error => console.log(error)); } update(){ this.router.navigate(['editCustomer/', this.customer.id]); } deleteCustomer(){ this.customerService.deleteCustomer(this.customer.id).subscribe(() => { this.listCustomer.reloadData(); }, error => console.log(error)); } }

Here, we are creating customer-list compoent

customer-list.component.html


<div *ngFor="let customer of customers | async"> <app-customer-details [customer]='customer'></app-customer-details> </div> <br><div *ngIf="customers"> <button type="button" class="button btn-danger" (click)='deleteCustomers()'>Delete All</button> </div>

customer-list.component.css


table, td, th { border: 1px solid #ddd; text-align: left; } table { border-collapse: collapse; width: 100%; } th, td { padding: 15px; }

customer-list.component.ts


import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs/internal/Observable'; import { Customer } from '../model/Customer'; import { CustomerService } from '../service/customer-service'; @Component({ selector: 'app-customer-list', templateUrl: './customer-list.component.html', styleUrls: ['./customer-list.component.css'] }) export class CustomerListComponent implements OnInit { customers: Observable<Customer[]>; private(private customerService: CustomerService) { } ngOnInit() { this.reloadData(); } deleteCustomers() { this.customerService.deleteAllCustomers().subscribe(() => { this.reloadData(); },error => console.log('ERROR: ' + error)); } reloadData() { this.customers = this.customerService.getCustomersList(); } }

Here, we are creating edit-customer compoent

edit-customer.html


<h2>Update Customer</h2> <div style="width: 300px;"> <form (ngSubmit)="update()" style="background: aliceblue; padding: 15px; border-radius: 10px;"> <div class="form-group"> <label>Firstname</label> <input type="text" class="form-control" id="firstname" required [(ngModel)]="customer.firstname" name="firstname"> </div> <div class="form-group"> <label>Lastname</label> <input type="text" class="form-control" id="lastname" required [(ngModel)]="customer.lastname" name="lastname"> </div> <div class="form-group"> <label>Age</label> <input type="text" class="form-control" id="age" required [(ngModel)]="customer.age" name="age"> </div> <button type="submit" class="btn btn-success"Submit</button> </form> </div>

edit-customer.ts


import { Component, OnInit } from '@angular/core'; import { Customer } from '../model/Customer'; import { CustomerService } from '../service/customer-service'; import { ActivatedRoute, Router } from '@angular/router'; @Component({ selector: 'app-add-customer', templateUrl: './add-customer.component.html', styleUrls: ['./add-customer.component.css'] }) export class AddCustomerComponent implements OnInit { customer: Customer = new Customer(); id = number; constructor(private customerService: CustomerService, private router: Router, private route: ActivatedRoute) { } ngOnInit() { this.id = this.route.snapshot.params.id; this.customerService.getCustomersById(this.id).subscribe(customer => { this.customer = customer; console.log(this.customer); }); } update(){ this.customerService.updateCustomer(this.id, this.customer).subscribe(customer => { this.customer = customer; this.router.navigate(['/customer']); }); this.customer = new Customer(); } }

Here, we are creating search-customer compoent

search-customer.component.html


<h2>Find By Age</h2> <div style="width: 300px;"> <form (ngSubmit)="onSubmit()"> <div class="form-group"> <label>Age</label> <input type="text" class="form-control" id="age" required [(ngModel)]="age" name="age"> </div> <div class="btn-group"> <button type="submit" class="btn btn-success">Submit</button> </div> </form> </div> <ul> <li *ngFor="let customer of customers"> <h3>{{customer.id}} - {{customer.firstname}} {{customer.lastname}} {{customer.age}}</h3> </li> </ul>

search-customer.component.ts


import { Component, OnInit } from '@angular/core'; import { Customer } from '../model/Customer'; import { CustomerService } from '../service/customer-service'; @Component({ selector: 'app-search-customer', templateUrl: './search-customer.component.html', styleUrls: ['./search-customer.component.css'] }) export class SearchCustomerComponent implements OnInit { age: number; customers: Customer[]; constructor(private customerService: CustomerService) { } ngOnInit() { this.age = 0; } searchCustomer(){ this.customerService.getCustomersByAge(this.age).subscribe(customers => this.customers = customers); } onSubmit(){ this.searchCustomer(); } }

Add the AppRoutingModule

In Angular, the best practice is to load and configure the router in a separate, top-level module that is dedicated to routing and imported by the root AppModule.


By convention, the module class name is AppRoutingModule and it belongs in the app-routing.module.ts in the src/app folder.

app-routing.module.ts


import { EditCustomerComponent } from './edit-customer/edit-customer.component'; import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { AddCustomerComponent} from './add-customer/add-customer.component'; import { CustomerListComponent } from './customer-list/customer-list.component'; import { SearchCustomerComponent } from './search-customer/search-customer.component'; const routes: Routes = [ {path: '', redirectTo: 'customer', pathMatch: 'full'}, {path: 'customer', component: CustomerListComponent}, {path: 'add', component: AddCustomerComponent}, {path: 'findbyage', component: SearchCustomerComponent}, {path: 'editCustomer/:id', component: EditCustomerComponent} ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }


NgModules and JavaScript modules

The NgModule system is different from and unrelated to the JavaScript (ES2015) module system for managing collections of JavaScript objects. These are complementary module systems that you can use together to write your apps.


In JavaScript each file is a module and all objects defined in the file belong to that module. The module declares some objects to be public by marking them with the export key word. Other JavaScript modules use import statements to access public objects from other modules.


app-module.ts


import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { AddCustomerComponent } from './add-customer/add-customer.component'; import { SearchCustomerComponent } from './search-customer/search-customer.component'; import { CustomerDetailsComponent } from './customer-details/customer-details.component'; import { CustomerListComponent } from './customer-list/customer-list.component'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; import { EditCustomerComponent } from './edit-customer/edit-customer.component'; @NgModule({ declarations: [ AppComponent, AddCustomerComponent, SearchCustomerComponent, CustomerDetailsComponent, CustomerListComponent, EditCustomerComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }


Conclusion

Now we have an overview of Angular 10 + Spring Boot CRUD example when building a CRUD App.

We also take a look at client-server architecture for REST API using Spring Web MVC & Spring Data JPA, as well as Angular 10 project structure for building a front-end app to make HTTP requests and consume responses.



Post a Comment

Previous Post Next Post


Follow us on facebook