Angular 6 SpringBoot CRUD DynamoDB Example

Angular Springboot CRUD Dynamodb

Tutorial: “Angular 6 SpringBoot CRUD DynamoDB Example”

In the tutorial, I introduce how to create an “SpringBoot Angular 6 DynamoDB CRUD Example” with POST/GET/PUT/DELETE requests to SpringBoot RestAPIs.

– Design overview system by Architecture Diagram that includes: Angular 6 Client, SpringBoot RestAPIs, and DynamoDB database.
– Implement Angular 6 CRUD Client with Angular 6 built-in HttpClient to communicate with server side.
– Implement SpringBoot RestAPIs that gets data from DynamoDB using Spring Data JPA and returns back data as Json format to requested Angular 6 Client.

You can check out the complete code of the application on this github repository.

Related posts:


What will we do?


Let’s start the tutorial “Angular 6 SpringBoot CRUD MSSQL” ->

Overall Angular 6 SpringBoot DynamoDB CRUD Architecture Application

Overall-Architecture-Angular-CRUD-DynamoDB-Application-with-SpringBoot-Fullstack-Example
Overall-Architecture-Angular-CRUD-DynamoDB-Application-with-SpringBoot-Fullstack-Example
  • We build backend SpringBoot Application that provides RestAPIs for POST/GET/PUT/DELETE Customer entities and store them in DynamoDB/PostgreSQL database.
  • We implement Angular 6 Application that use Angular 6 HTTPClient to interact (call/receive requests) with SpringBoot backend and display corresponding page view in browser.

Overview SpringBoot CRUD DynamoDB Backend Architecture

SpringBoot-DynamoDB-RestAPIs-Backend-Architecture-Design
SpringBoot-DynamoDB-RestAPIs-Backend-Architecture-Design
  • For building RestAPIs in SpringBoot application, we use Spring MVC Web.
  • For interacting with database DynamoDB/PostgreSQL, we use Spring JPA.
  • We implement RestAPI’s URL in RestAPIController.java file to process bussiness logic.
  • For manipulating database’s records, we define a JPA model for mapping field data and use a JPA CRUD repository to do CRUD operation with DynamoDB/PostgreSQL.

– SpringBoot Project Structure for tutorial “Angular 6 SpringBoot CRUD MSSQL”

Angular 6 SpringBoot CRUD  DynamoDB Example - SpringBoot RestAPI Backend Project Structure
SpringBoot Backend Project Structure
  • models package defines Customer model and Message response class.
  • repository package defines Spring JPA repository class CustomerRepository to do CRUD operation with database.
  • service package defines a middleware class CustomerServices between Controller and Repository.
  • controller package defines a RestAPI Controller RestAPIController to handle POST/GET/PUT/DELETE request.

Overview Angular 6 CRUD Architecture Design – Angular 6 SpringBoot CRUD DynamoDB RestAPI

Angular 6 CRUD Application - Frontend Design Architecture
Angular 6 CRUD Application – Frontend Design Architecture

Angular 6 CRUD Application is designed with 3 main layers:

  • Service Layer is used to define Angular 6 Common Services and HttpClient Services to interact with RestAPIs
  • Component Layer is used to define Angular 6 Components to show views in Browser for interacting with Users
  • Router Layer is used to route URLs mapping with the corresponding Angular 6 Components

Angular 6 Project Structure:

Angular 6 SpringBoot CRUD  DynamoDB Example - Angular 6 CRUD Application - Project Structure
Angular 6 CRUD Application – Project Structure

Angular 6 CRUD Application defines 3 components, 2 services, 1 routers, and 2 data models:

– Components:

  • add-customer component is used to add a new customer to system
  • list-customer component is used to show all customers on view pages, delete a customer and update a customer
  • message component is used to define a view to show logging message on browser

– Services:

  • customer.service.ts defines POST/GET/PUT/DELETE HTTP requests to SpringBoot RestAPIs with the built-in Angular 6 HttpClient.
  • message.service.ts defines an array storage to log all messages when Angular 6 CRUD App running

– Router: app-routing.module.ts defines how to map a corresponding Angular 6 component with an URL.

– Models:

  • customer.ts defines the main data model of our application.
  • message.ts defines the response data model between SpringBoot and Angular 6 application.

Goal – Angular 6 SpringBoot CRUD DynamoDB RestAPI

– Add new Customer: from Angular 6 to SpringBoot and save to DynamoDB.

Angular 6 CRUD SpringBoot  DynamoDB App - Add new customers
Angular 6 CRUD App – Add new customers

– List All Customers: from Angular 6 calls SpringBoot RestAPI to get customer from DynamoDB.

Angular 6 CRUD SpringBoot  DynamoDB Application - List All Customer
Angular 6 CRUD Application – List All Customer

– Details a Customer: from Angular 6 calls get http request from SpringBoot RestAPI to get a record in DynamoDB database

Angular 6 CRUD SpringBoot  DynamoDB App - Details a Customer
Angular 6 CRUD App – Details a Customer

– Update a Customer: from Angular 6 calls a put http request from SpringBoot RestAPI to update a record in DynamoDB database.

Angular 6 CRUD SpringBoot  DynamoDB Application - Update a Customer
Angular 6 CRUD Application – Update a Customer

– Delete a Customer: from Angular 6 calls a delete http request from SpringBoot RestAPI to delete a record in DynamoDB database.

Angular 6 CRUD App - Delete a Customer successfully
Angular 6 CRUD SpringBoot DynamoDB App – Delete a Customer successfully

– Check database records: do a get request from Angular 6 to SpringBoot RestAPI.

Angular 6 CRUD App - Check database records
Angular 6 CRUD App – Check database records

Video Guide – Angular 6 SpringBoot CRUD DynamoDB Example FullStack DEBUG

Create SpringBoot Application

For building SpringBoot RestAPIs CRUD Application, we need Spring Web, Spring JPA and DynamoDB, so we add below dependencies in pom.xml file:


<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<artifactId>aws-java-sdk-dynamodb</artifactId>
		<groupId>com.amazonaws</groupId>
	<version>1.11.34</version>
</dependency>

<dependency>
	<groupId>com.github.derjust</groupId>
	<artifactId>spring-data-dynamodb</artifactId>
	<version>4.5.0</version>
</dependency>

SpringBoot CRUD DynamoDB/PostgreSQL Database Configuration

SpringBoot helps us to create a datasource by simple configuration in application.properties file. We use the spring.datasource.* to setup the url, username and password for Spring datasource bean as above.

Open application.properties:


amazon.dynamodb.endpoint=http://localhost:8000/
amazon.aws.accesskey=jsa
amazon.aws.secretkey=javasampleapproach

Under package config, create DynamoDBConfig class:


package com.javasampleapproach.dynamodb.config;

import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.util.StringUtils;

@Configuration
@EnableDynamoDBRepositories(basePackages = "com.javasampleapproach.dynamodb.repo")
public class DynamoDBConfig {

	@Value("${amazon.dynamodb.endpoint}")
	private String dBEndpoint;

	@Value("${amazon.aws.accesskey}")
	private String accessKey;

	@Value("${amazon.aws.secretkey}")
	private String secretKey;

	@Bean
	public AmazonDynamoDB amazonDynamoDB() {
		AmazonDynamoDB dynamoDB = new AmazonDynamoDBClient(amazonAWSCredentials());

		if (!StringUtils.isNullOrEmpty(dBEndpoint)) {
			dynamoDB.setEndpoint(dBEndpoint);
		}

		return dynamoDB;
	}

	@Bean
	public AWSCredentials amazonAWSCredentials() {
		return new BasicAWSCredentials(accessKey, secretKey);
	}
}

SpringBoot Define Spring JPA Data Model

We create a Customer model class with 5 attributes:

  • id
  • firstname
  • lastname
  • address
  • age

– Coding:

Under package model, create Customer class:


package com.javasampleapproach.dynamodb.model;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;

@DynamoDBTable(tableName = "Customer")
public class Customer {

	private String id;
	private String firstName;
	private String lastName;
	private int age;
	private String address;

	public Customer() {
	}

	public Customer(String id, String firstName, String lastName, int age, String address) {
		this.id = id;
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age,
		this.address = address
	}

	@DynamoDBHashKey(attributeName = "Id")
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	@DynamoDBAttribute(attributeName = "FirstName")
	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	@DynamoDBAttribute(attributeName = "LastName")
	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@DynamoDBAttribute(attributeName = "age")
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.lastName = lastName;
	}
	
	@DynamoDBAttribute(attributeName = "address")
	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
	
	@Override
	public String toString() {
		return String.format("Customer[id=%s, firstName='%s', lastName='%s', age='%d', address='%s']", id, firstName, lastName, age, address);
	}
}

@DynamoDBAttribute:


@Retention(value=RUNTIME)
 @Target(value={FIELD,METHOD})
public @interface DynamoDBAttribute

– Interface for marking a class property as an attribute in a DynamoDB table. Applied to the getter method or the class field for a modeled property. If the annotation is applied directly to the class field, the corresponding getter and setter must be declared in the same class.
– This annotation is optional when the name of the DynamoDB attribute matches the name of the property declared in the class. When they differ, use this annotation with the attributeName() parameter to specify which DynamoDB attribute this property corresponds to. Furthermore, the DynamoDBMapper class assumes Java naming conventions, and will lower-case the first character of a getter method’s property name to determine the name of the property. E.g., a method getValue() will map to the DynamoDB attribute “value”. Similarly, a method isValid() maps to the DynamoDB attribute “valid”.

SpringBoot Implement JPA Repository and Service

For doing CRUD operations with database, we define an interface CustomerRepository that extends class JpaRepository:


package com.loizenai.dynamodb.repo;

import java.util.List;

import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;

import com.javasampleapproach.dynamodb.model.Customer;

@EnableScan
public interface CustomerRepository extends CrudRepository {

	List findByLastName(String lastName);
}

– We implement a middleware class service CustomerServices between CustomerRepository and RestAPIController:

package com.example.loizenai.crudapp.service;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.loizenai.crudapp.model.Customer;
import com.example.loizenai.crudapp.repository.CustomerRepository;

/**
 * @Copyright by https://loizenai.com
 * @author https://loizenai.com
 *	      youtube loizenai
 */

@Service
public class CustomerServices {
	
	@Autowired CustomerRepository repository;
	
	public Customer saveCustomer(Customer customer) {
		return repository.save(customer);
	}
	
	public List<Customer> getCustomerInfos(){
		return repository.findAll();
	}
	
	public Optional<Customer> getCustomerById(long id) {
		return repository.findById(id);
	}
	
	public boolean checkExistedCustomer(long id) {
		if(repository.existsById((long) id)) {
			return true;
		}
		return false;
	}
	
	public Customer updateCustomer(Customer customer) {
		return repository.save(customer);		
	}
	
	public void deleteCustomerById(long id) {
		repository.deleteById(id);
	}
}

SpringBoot Implement RestAPIs Controller – POST/GET/PUT/DELETE

We implement a RestAPI Controller RestAPIController to handle POST/GET/PUT/DELETE request-mapping with 5 APIs:

  • addNewCustomer(@RequestBody Customer customer) handles POST request to add a new customer.
  • ResponseEntity retrieveCustomerInfo() handles GET request to retrieve all customers.
  • getCustomerById(@PathVariable long id) handles GET request to get a customer by given id.
  • updateCustomerById(@RequestBody Customer _customer, @PathVariable long id) handles PUT request to update a customer
  • deleteCustomerById(@PathVariable long id) handles DELETE request to delete a Customer from database
SpringBoot RestAPIs Controller Functions
SpringBoot RestAPIs Controller Functions
@RestController
@RequestMapping("/api/customer")
public class RestAPIController {
    @Autowired
    CustomerServices customerServices;
     ...
}

SpringBoot CRUD RestAPI: Add New Customer Controller

@PostMapping("/create")
public ResponseEntity<Message> addNewCustomer(@RequestBody Customer customer) {
	try {
		Customer returnedCustomer = customerServices.saveCustomer(customer);
		
		return new ResponseEntity<Message>(new Message("Upload Successfully!", 
										Arrays.asList(returnedCustomer), ""), HttpStatus.OK);
	}catch(Exception e) {
		return new ResponseEntity<Message>(new Message("Fail to post a new Customer!", 
										null, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);			
	}
}

SpringBoot CRUD RestAPI Get a Customer by ID Controller

@GetMapping("/findone/{id}")
public ResponseEntity<Message> getCustomerById(@PathVariable long id) {
	try {
		Optional<Customer> optCustomer = customerServices.getCustomerById(id);
		
		if(optCustomer.isPresent()) {
			return new ResponseEntity<Message>(new Message("Successfully! Retrieve a customer by id = " + id,
														Arrays.asList(optCustomer.get()), ""), HttpStatus.OK);
		} else {
			return new ResponseEntity<Message>(new Message("Failure -> NOT Found a customer by id = " + id,
					null, ""), HttpStatus.NOT_FOUND);
		}
	}catch(Exception e) {
		return new ResponseEntity<Message>(new Message("Failure",
				null, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

SpringBoot CRUD RestAPI Get All Customers Controller

@GetMapping("/retrieveinfos")
public ResponseEntity<Message> retrieveCustomerInfo() {
	
	try {
		List<Customer> customerInfos = customerServices.getCustomerInfos();
		
		return new ResponseEntity<Message>(new Message("Get Customers' Infos!", 
											customerInfos, ""), HttpStatus.OK);
	}catch(Exception e) {
		return new ResponseEntity<Message>(new Message("Fail!",
											null, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

SpringBoot CRUD RestAPI Delete a Customer Controller

@DeleteMapping("/deletebyid/{id}")
public ResponseEntity<Message> deleteCustomerById(@PathVariable long id) {
	try {
		// checking the existed of a Customer with id
		if(customerServices.checkExistedCustomer(id)) {
			customerServices.deleteCustomerById(id);
			
			return new ResponseEntity<Message> (new Message("Successfully! Delete a Customer with id = " + id, 
													null, ""), HttpStatus.OK);
		}else {
			return new ResponseEntity<Message>(new Message("Failer! Can NOT Found a Customer "
													+ "with id = " + id, null, ""), HttpStatus.NOT_FOUND);
		}
	}catch(Exception e) {
		return new ResponseEntity<Message>(new Message("Failure",
				null, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

SpringBoot CRUD RestAPI Update a Customer Controller

@PutMapping("/updatebyid/{id}")
public ResponseEntity<Message> updateCustomerById(@RequestBody Customer _customer, 
																@PathVariable long id) {
	try {
		if(customerServices.checkExistedCustomer(id)) {
			Customer customer = customerServices.getCustomerById(id).get();
			
			//set new values for customer
			customer.setFirstname(_customer.getFirstname());
			customer.setLastname(_customer.getLastname());
			customer.setAddress(_customer.getAddress());
			customer.setAge(_customer.getAge());

			// save the change to database
			customerServices.updateCustomer(customer);
			
			return new ResponseEntity<Message>(new Message("Successfully! Updated a Customer "
																	+ "with id = " + id,
																Arrays.asList(customer), ""), HttpStatus.OK);
		}else {
			return new ResponseEntity<Message>(new Message("Failer! Can NOT Found a Customer "
					+ "with id = " + id,
				null, ""), HttpStatus.NOT_FOUND);
		}
	}catch(Exception e) {
		return new ResponseEntity<Message>(new Message("Failure",
				null, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);			
	}
}

SpringBoot CRUD DynamoDB/PostgreSQL RestAPI Backend Testing – Angular 6 SpringBoot CRUD DynamoDB RestAPI

– Run DynamoDB:


java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

– Create Customer Table:


aws dynamodb create-table --table-name Customer --attribute-definitions AttributeName=Id,AttributeType=S --key-schema AttributeName=Id,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 --endpoint-url http://localhost:8000

Response is like:


{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/Customer",
        "AttributeDefinitions": [
            {
                "AttributeName": "Id",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 1,
            "LastIncreaseDateTime": 0.0,
            "ReadCapacityUnits": 1,
            "LastDecreaseDateTime": 0.0
        },
        "TableSizeBytes": 0,
        "TableName": "Customer",
        "TableStatus": "ACTIVE",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Id"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1514538274.168
    }
}

– Config maven build:
clean install
– Run project with mode Spring Boot App
– Check results:

Request 1
http://localhost:8080/save
The browser returns Done and if checking database with Customer table, we can see some data rows has been added:
SpringData DynamoDB CRUD Example - spring-data-dynamodb-table-result-save

More at: SpringData DynamoDB CRUD Example | SpringBoot

Angular 6 SpringBoot CRUD DynamoDB Application Overview

Angular 6 CRUD Application - Frontend Design Architecture
Angular 6 CRUD Application – Frontend Design Architecture

– For more details, we go back to the session: Angular 6 CRUD Design

Create Angular 6 CRUD Application

We create Angular 6 CRUD project by commandline: ng new AngularHttpclient.
– Create 3 components AddCustomer, ListCustomers, Message by cmd:


ng g component AddCustomer
ng g component ListCustomers
ng g component Message

– Create 2 Angular 6 services CustomerService, MessageService by cmd:


ng g service customer
ng g service message

– Create 2 models Customer and Message by cmd:


ng g class customer;
ng g class message;

Angular 6 Create Data Model

We define Customer class with 5 attributes:

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

Angular 6 Create Message Model

We define Message class as below:

import { Customer } from './customer';

export class Message {
    message: string;
    error: string;
    customers: Customer[];
}

Angular 6 SpringBoot CRUD DynamoDB RestAPI tutorial – Angular 6 Implement Angular 6 HttpClient Customer Service

For interacting with Backend RestAPIs, we use Angular 6 built-in Httpclient service:

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

  private baseUrl = 'http://localhost:8080/api/customers';

  constructor(private http: HttpClient) { }
  
  ...

To handle Error, we implement a function private handleError(error: HttpErrorResponse):

private handleError(error: HttpErrorResponse) {
  if (error.error instanceof ErrorEvent) {
    // A client-side or network error occurred. Handle it accordingly.
    console.error('An error occurred:', error.error.message);
  } else {
    // The backend returned an unsuccessful response code.
    // The response body may contain clues as to what went wrong,
    console.error(
      `Backend returned code ${error.status}, ` +
      `body was: ${error.error}`);
  }
  // return an observable with a user-facing error message
  return throwError(
    'Something bad happened; please try again later.');
};

Angular 6 HttpClient POST Request – Add new Customer

createCustomer(customer: Customer): Observable<Message> {
    return this.http.post<Message>(`${this.baseUrl}` + `/create`, customer)
                .pipe(
                  retry(3),
                  catchError(this.handleError)
                );
}

– The above function posts a Customer to SpringBoot backend server at URL http://localhost:8080/api/customers/create
retry(3) is used to retry a failed request up to 3 times

Angular 6 HttpClient GET Request – Retrieve Customers

– Retrieve all Customers from SpringBoot backend at RestAPI by a GET request at URL http://localhost:8080/api/customers/retrieveinfos.

retrieveAllCustomers(): Observable {
    return this.http.get(`${this.baseUrl}` + `/retrieveinfos`)
                  .pipe(
                    retry(3),
                    catchError(this.handleError)
                  );
}

Angular 6 HttpClient PUT Request – Modify a Customer

– Update a Customer with Angular 6 Httpclient by a PUT request at URL:
http://localhost:8080/api/customers/updatebyid/{id}

updateCustomer(customer: Customer): Observable<Message> {
    return this.http.put<Message> (`${this.baseUrl}` + `/updatebyid/` + customer.id, customer)
      .pipe(
          retry(3),
          catchError(this.handleError)
        );
}

Angular 6 HttpClient DELETE Request – Delete a Customer

– Delete a Customer by a given id with Angular 6 Httpclient by a DELETE request at URL:
http://localhost:8080/api/customers/deletebyid/{id}:


deleteCustomer(id: number): Observable<Message> {
    return this.http.delete<Message>(`${this.baseUrl}` + `/deletebyid/` + id)
          .pipe(
            retry(3),
            catchError(this.handleError)  
          );
}

Angular 6 Implement Message Service

For tracking the proccessing of each proccessing in Angular 6 CRUD Application, We implement a Message service to store tracing-logs message then display them on Html.

The message.service.ts has an string array messages to store tracing-log messages and 2 functions: add(message: string) and clear()

– Coding:


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

@Injectable({
  providedIn: 'root'
})
export class MessageService {
  messages: string[] = [];

  add(message: string) {
    this.messages.push(message);
  }

  clear(){
    this.messages = [];
  }
}

Angular 6 Implement Component: Add Customer

AddCustomerComponent is used to post a new Customer to SpringBoot backend server.
– We have 2 parts:

  • add-customer.component.ts file
  • add-cusomer.component.html file

Angular 6 Implement add-customer.component.ts

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
import { Message } from '../message';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-add-customer',
  templateUrl: './add-customer.component.html'
})
export class AddCustomerComponent implements OnInit {
  customer: Customer;
  /**
   * Constructing Http Customer Service
   * @param customerService 
   */
  constructor(private customerService: CustomerService,
                private messageService: MessageService) { }

  ngOnInit(): void {
    this.customer = new Customer();
  }

  /**
   * Store a Customer to backend server
   */
  save() {
    this.customerService.createCustomer(this.customer)
          .subscribe((message: Message) => {
            console.log(message);
            let customer = message.customers[0];
            let msg = "Success -> Post a Customer: " 
                + "<ul>"
                    + "<li>id: " + customer.id + "</li>"  
                    + "<li>firstname: " + customer.firstname + "</li>"
                    + "<li>lastname: " + customer.lastname + "</li>"
                    + "<li>age: " + customer.age + "</li>"
                    + "<li>address: " + customer.address + "</li>"
                + "</ul>";

            this.messageService.add(msg);
          }, error => {
            console.log(error);
            let msg = "Error! -> Action Posting a Customer:" 
                      + "<ul>"
                        + "<li>id = " + this.customer.id + "</li>"  
                        + "<li>firstname = " + this.customer.firstname + "</li>"
                        + "<li>lastname = " + this.customer.lastname + "</li>"
                        + "<li>age = " + this.customer.age + "</li>"
                        + "<li>address = " + this.customer.address + "</li>"
                      + "</ul>";

            this.messageService.add(msg);
          });
  }

  reset(){
    this.customer = new Customer();
  }

  /**
   * Function handles form submitting
   */
  onSubmit() {
    this.save();
    this.reset();
  }
}

Angular 6 Implement add-customer.component.html view

<h2>Create Customer</h2>
<div>
  <form (ngSubmit)="onSubmit()"> 
    <!-- First name -->   
    <div class="form-group">
      <label for="firstname">First Name:</label>
      <input type="text" class="form-control" placeholder="Enter Firstname" 
                id="firstname" required [(ngModel)]="customer.firstname" name="firstname">
    </div>
    <!-- Last name -->
    <div class="form-group">
        <label for="lastname">Last Name:</label>
        <input type="text" class="form-control" placeholder="Enter Lastname" 
                  id="lastname" required [(ngModel)]="customer.lastname" name="lastname">
    </div>  
    <!-- Address -->
    <div class="form-group">
        <label for="address">Address:</label>
        <input type="text" class="form-control" placeholder="Enter Address" 
                  id="address" required [(ngModel)]="customer.address" name="address">
    </div>        
    
    <!-- Age -->
    <div class="form-group">
      <label for="age">Age</label>
      <input type="number" class="form-control" placeholder="Enter Age" 
                  id="age" required [(ngModel)]="customer.age" name="age">
    </div>
 
    <button type="submit" class="btn btn-success">Submit</button>
  </form>
</div>
<app-message></app-message>

Angular 6 Implement Component: List Customers

ListCustomersComponent has 4 main functions:

  • Show all Customers
  • Show details a Customers
  • Delete a Customer
  • Update a Customer

Angular 6 Implement list-customers.component.ts

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { MessageService } from '../message.service';
import { CustomerService } from '../customer.service';
import { Message } from '../message';

@Component({
  selector: 'app-list-customers',
  templateUrl: './list-customers.component.html'
})
export class ListCustomersComponent implements OnInit {

  customers: Array<Customer> = [];
  showCustomer: Customer;
  isSelected: boolean = false;
  deletedCustomer: Customer;
  returnedMessage: string;

  constructor(private customerService: CustomerService,
                private messageService: MessageService) { }

  setCustomerDetails(customer: Customer){
    this.isSelected=!this.isSelected;
    if(this.isSelected){
      this.showCustomer = customer;
    }else{
      this.showCustomer = undefined;
    }
  }

  /**
   * Set deletedCustomer and reset returnedMessage = undefined
   * @param deleteCustomer
   */
  prepareDeleteCustomer(deleteCustomer: Customer){
    //assign delete-Customer
    this.deletedCustomer = deleteCustomer;
    // reset returned-Message
    this.returnedMessage = undefined;
  }

  /**
   * Delete a Customer by ID
   */
  deleteCustomer(){

    console.log("--- Access delelteCustomer() function");

    this.customerService.deleteCustomer(this.deletedCustomer.id)
                      .subscribe((message: Message) => {
                          console.log(message);
                          // remove a deletedCustomer from customers list on view
                          this.customers = this.customers.filter(customer => {
                            return customer.id != this.deletedCustomer.id;
                          })

                          // set a showing message in delete modal
                          this.returnedMessage = message.message;

                          // just reset showCustomer for not showing on view
                          this.showCustomer = undefined;

                          // add the delete message to message app for showing
                          this.messageService.add(message.message);
                        },
                        (error) => {
                          console.log(error);
                          let errMsg: string = "Error! Details: " + error;
                          this.messageService.add(errMsg);
                        });
  }

  /**
   * Update Customer function
   */
  updateCustomer() {
    this.customerService.updateCustomer(this.showCustomer)
                      .subscribe((message: Message) => {
                        console.log(message);
                        // update customers list
                        this.customers.map(x => {
                          if(x.id == this.showCustomer.id){
                            x = this.showCustomer;
                          }
                        });

                        let msg: string = "Update Successfully! -> New Customer's properties: <br>"
                                          + "<ul>"
                                            + "<li>" + "id: " + this.showCustomer.id + "</li>"
                                            + "<li>" + "firstname: " + this.showCustomer.firstname + "</li>"
                                            + "<li>" +  "lastname: " + this.showCustomer.lastname + "</li>"
                                            + "<li>" +  "age: " + this.showCustomer.age + "</li>"
                                            + "<li>" +  "address: " + this.showCustomer.address + "</li>"
                                          + "</ul>";
                        this.messageService.add(msg);
                      }
                      , (error) => {
                        console.log(error);
                        let errMsg = "Update Fail ! Error = " + error;
                        this.messageService.add(errMsg);
                      });
  }

  /**
   * Retrieve all Customer from Backend
   */
  retrieveAllCustomers() {
    this.customerService.retrieveAllCustomers()
                  .subscribe((message: Message) => {
                    console.log(message);
                    this.customers = message.customers;
                  }
                  , (error) => {
                    console.log(error);
                  });
  }

  ngOnInit(): void {
    this.retrieveAllCustomers();
  }
}

Angular 6 Implement list-customers.component.html

<div *ngIf="customers.length">
    <h3>Customers</h3>
    <br>
    <table class="table table-hover table-sm">
        <thead class="thead-dark">
          <tr>
            <th>Id</th>
            <th>Firstname</th>
            <th>Address</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
            <tr *ngFor="let customer of customers">
              <td>
                <button type="button" class="btn btn-primary" (click)="setCustomerDetails(customer)">
                  {{customer.id}}
                </button>
              </td>
              <td>{{customer.firstname}}</td>
              <td>{{customer.address}}</td>
              <td>
                <button type="button" class="btn btn-danger" 
                  data-toggle="modal" data-target="#delete-modal" 
                                (click)=prepareDeleteCustomer(customer) >&times;</button>
              </td>
            </tr>
        </tbody>
    </table>
</div>

<!-- The Modal -->
<div class="modal fade" id="delete-modal">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
    
    <!-- Modal Header -->
    <div class="modal-header">
      <h4 class="modal-title">Delete!</h4>
      <button type="button" class="close" data-dismiss="modal">&times;</button>
    </div>
    
    <!-- Modal body -->
    <div class="modal-body">
        <div *ngIf="deletedCustomer">
          <p [hidden] = "returnedMessage">
            Do you want delete a customer with id = {{deletedCustomer.id}}
          </p>
          <p [hidden] = "!returnedMessage">
            {{returnedMessage}}
          </p>
        </div>
    </div>
    
    <!-- Modal footer -->
    <div class="modal-footer">
      <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
      <button [hidden] = "returnedMessage" type="button" class="btn btn-danger" (click)="deleteCustomer()">Delete</button>
    </div>				
    </div>
  </div>
  </div>

<div *ngIf="showCustomer">
    <h3>Update Customer</h3>
    <form (ngSubmit)="updateCustomer()"> 
        <!-- ID -->   
        <div class="form-group">
          <label for="id">Id:</label>
          <input type="numer" class="form-control"
                    id="id" required [(ngModel)]="showCustomer.id" name="id" disabled>
        </div>      
        <!-- First name -->   
        <div class="form-group">
          <label for="firstname">First Name:</label>
          <input type="text" class="form-control" placeholder="Enter Firstname" 
                    id="firstname" required [(ngModel)]="showCustomer.firstname" name="firstname">
        </div>
        <!-- Last name -->
        <div class="form-group">
            <label for="lastname">Last Name:</label>
            <input type="text" class="form-control" placeholder="Enter Lastname" 
                      id="lastname" required [(ngModel)]="showCustomer.lastname" name="lastname">
        </div>  
        <!-- Address -->
        <div class="form-group">
            <label for="address">Address:</label>
            <input type="text" class="form-control" placeholder="Enter Address" 
                      id="address" required [(ngModel)]="showCustomer.address" name="address">
        </div>        
        
        <!-- Age -->
        <div class="form-group">
          <label for="age">Age</label>
          <input type="number" class="form-control" placeholder="Enter Age" 
                      id="age" required [(ngModel)]="showCustomer.age" name="age">
        </div>
     
        <button type="submit" class="btn btn-success">Update</button>
      </form>
</div>
<app-message></app-message>


<script>
  let pathname = window.location.pathname;
  if(pathname == ""){
      $(".nav .nav-item a:first").addClass("active");
      $(".nav .nav-item a:last").removeClass("active");
  } else if (pathname == "/customers") {
      $(".nav .nav-item a:last").addClass("active");
      $(".nav .nav-item a:first").removeClass("active");
  }
  alert("ok");
</script>

Angular 6 SpringBoot CRUD DynamoDB RestAPI Tutorial – Angular 6 Implement Component: Message Component

MessageComponent is used to show all tracing-log messages in html view.

– Implement message.component.ts:

import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-message',
  templateUrl: './message.component.html'
})
export class MessageComponent {
  constructor(public messageService: MessageService) {}
}

– Implement message.component.html:

<div *ngIf="messageService.messages.length">
    <h3>Messages</h3>
    <button type="button" class="btn btn-secondary" (click)="messageService.clear()">clear</button>
    <br>
    <ol>
      <li *ngFor='let message of messageService.messages'>
        <div [innerHTML]="message">
        </div>
      </li>
    </ol>
  </div>

Angular 6 Configure App Routing Module

To handle the navigation from one view to the next, you use the Angular 6 router. The router enables navigation by interpreting a browser URL as an instruction to change the view.

The following command uses the Angular 6 CLI to generate a basic Angular 6 app with an app routing module, called AppRoutingModule, which is an NgModule where you can configure your routes.

ng new routing-app --routing

How to Define a route? -> There are three fundamental building blocks to creating a route.

1. Import the AppRoutingModule into AppModule and add it to the imports array.
The Angular 6 CLI performs this step for you. However, if you are creating an app manually or working with an existing, non-CLI app, verify that the imports and configuration are correct.


import { AppRoutingModule } from './app-routing.module';
...

@NgModule({
  declarations: [
	...
  ],
  imports: [
	...
    AppRoutingModule,
    ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2. Define your routes in your Routes array

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AddCustomerComponent } from './add-customer/add-customer.component';
import { ListCustomersComponent } from './list-customers/list-customers.component';

const routes: Routes = [
  { 
    path: '', 
    component: AddCustomerComponent 
  },
  { 
    path: 'customers', 
    component: ListCustomersComponent 
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

3. Add your routes to your application.
In the index.html file, we add below html code for navigating URL:


<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
  <ul class="navbar-nav">
    <li class="nav-item" id="li_add_customer">
      <a class="nav-link" href="">Add Customer</a>
    </li>
    <li class="nav-item" id="li_list_customers">
      <a class="nav-link" href="/customers">List Customers</a>
    </li>
  </ul>
</nav>

Next, update your component template to include . This element informs Angular 6 to update the application view with the component for the selected route. So in main component,open app.component.ts file, add the tag:


<router-outlet></router-outlet>

Modify Angular 6 index.html view page

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularHttpclient</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
  <!-- jQuery library -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <!-- Popper JS -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <!-- Latest compiled JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
</head>
<body>
  <div class="container" >  
    <div class="col-sm-5" style="background-color: #ffffcc; margin:10px;padding:10px; border-radius: 5px">
      <nav class="navbar navbar-expand-sm bg-primary navbar-dark">
        <ul class="navbar-nav">
          <li class="nav-item" id="li_add_customer">
            <a class="nav-link" href="">Add Customer</a>
          </li>
          <li class="nav-item" id="li_list_customers">
            <a class="nav-link" href="/customers">List Customers</a>
          </li>
        </ul>
      </nav>
      <app-root></app-root>
    </div>
  </div>
  <script>
    $(document).ready(function() {
      (function(){
        let pathname = window.location.pathname;
        if(pathname == "/"){
            $("#li_add_customer").addClass("active");
            $("#li_list_customers").removeClass("active");
        } else if (pathname == "/customers") {
            $("#li_list_customers").addClass("active");
            $("#li_add_customer").removeClass("active");
        } 
      })();
    });
  </script>
</body>
</html>

Angular 6 CRUD Application Testing – Angular 6 SpringBoot CRUD MSSQL

– Testcase 1 – Add New Customer:

Angular 6 CRUD Application - Testcase 1 - POST a Customer - Network Logs
Angular 6 CRUD Application – Testcase 1 – POST a Customer – Network Logs
Angular 6 CRUD Application - Testcase 1 - POST a Customer - Successfully
Angular 6 CRUD Application – Testcase 1 – POST a Customer – Successfully

– Testcase 2 – Retrieve All Customers

Angular 6 SpringBoot CRUD  DynamoDB Example - Angular 6 CRUD Application - Testcase 2 - GET all Customers - Network Logs
Angular 6 CRUD Application – Testcase 2 – GET all Customers – Network Logs
Angular 6 CRUD Application - Testcase 2 - GET all Customers - Successfully
Angular 6 CRUD Application – Testcase 2 – GET all Customers – Successfully

– Testcase 3 – Update a Customer:

Angular 6 SpringBoot CRUD  DynamoDB Example - Testcase 3 - UPDATE a Customer with id = 3 - Network Logs
Angular 6 CRUD Application – Testcase 3 – UPDATE a Customer with id = 3 – Network Logs
Angular 6 CRUD Application - Testcase 3 - UPDATE a Customer with id = 3 - Successfully
Angular 6 CRUD Application – Testcase 3 – UPDATE a Customer with id = 3 – Successfully

– Testcase 4 – Delete a Customer:

Angular 6 CRUD Application - Testcase 4 - DELETE a Customer - Successfully
Angular 6 CRUD Application – Testcase 4 – DELETE a Customer – Successfully
Angular 6 CRUD App - Check database records
Angular 6 CRUD App – Check database records

Sourcecode – Angular 6 SpringBoot CRUD DynamoDB RestAPI

Below are all sourcecodes (includes github) for the tutorial: “SpringBoot + Angular 6 CRUD Example with DynamoDB” :

– SpringBoot backend’s sourcecode with below implemented features:

SpringBootCRUDApplication

– GitHub Sourcecode for SpringBoot Angular 6 CRUD Example:

SpringBoot-CRUD-mysql-Application – GitHub Sourcecode

– Angular 6 CRUD Application Sourcecode with below implemented features:

AngularCrudApplication

– GitHub Sourcecode

Angular 6 Crud DynamoDB Example Application – GitHub

Related posts with tutorial “Angular 6 SpringBoot CRUD MSSQL”:

SpringBoot RestAPI with DynamoDB database
Angular 6 SpringBoot MySQL CRUD Example
Angular 6 SpringBoot MySQL CRUD Example
Angular 11 SpringBoot CRUD MySQL
Angular SpringBoot CRUD MySQL Example
Angular SpringBoot CRUD DynamoDB
Angular 12 SpringBoot CRUD DynamoDB
Angular 11 SpringBoot CRUD DynamoDB Example
Angular 10 SpringBoot CRUD DynamoDB
SpringBoot React DynamoDB CRUD Example
Angular 9 SprigBoot CRUD DynamoDB
Angular 8 SpringBoot DynamoDB CRUD Example

Leave a Reply

Your email address will not be published. Required fields are marked *