You are currently viewing Angular 9 and Spring Boot CRUD Tutorial – Feature 3 Update expense details

Angular 9 and Spring Boot CRUD Tutorial – Feature 3 Update expense details

Hey in the previous post we covered saving the expense details to the database, in this post we will cover updating the expense details. We will continue with the same example which we created in the previous post. Let’s begin…




We will cover the following topics

  • Create rest endpoint to get the single expense
  • We will make HTTP GET request from an angular application
  • We will update the expense details

First, let’s start with creating rest endpoint in spring boot application – inside the ExpenseService.java declare a method to get a single expense object.

Open, ExpenseService.java


package in.bushansirgur.expensetracker.service;

import java.util.List;

import in.bushansirgur.expensetracker.model.Expense;

public interface ExpenseService {
	
	List<Expense> findAll();
	
	Expense save(Expense expense);
	
	Expense findById(Long id);
	
}

Now we need to provide implementation by overriding it inside the ExpenseServiceImpl.java class

package in.bushansirgur.expensetracker.service;

import java.util.List;

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

import in.bushansirgur.expensetracker.model.Expense;
import in.bushansirgur.expensetracker.repository.ExpenseRepository;

@Service
public class ExpenseSerivceImpl implements ExpenseService {

	@Autowired
	ExpenseRepository expenseRepository;
	
	@Override
	public List<Expense> findAll() {
		return expenseRepository.findAll();
	}

	@Override
	public Expense save(Expense expense) {
		expenseRepository.save(expense);
		return expense;
	}

	@Override
	public Expense findById(Long id) {
		if(expenseRepository.findById(id).isPresent()){
			return expenseRepository.findById(id).get();
		}
		return null;
	}

}

Alright, now we have service method to get a single expense object, all we need to do is call this service method inside the ExpenseController.java

Open, ExpenseController.java


package in.bushansirgur.expensetracker.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import in.bushansirgur.expensetracker.model.Expense;
import in.bushansirgur.expensetracker.service.ExpenseService;

@CrossOrigin("*")
@RestController
@RequestMapping("/api/v1")
public class ExpenseController {

	@Autowired
	ExpenseService expenseService;
	
	@GetMapping("/expenses")
	public ResponseEntity<List<Expense>> get() {
		List<Expense> expenses = expenseService.findAll();
		return new ResponseEntity<List<Expense>>(expenses, HttpStatus.OK);
	}
	
	@PostMapping("/expenses")
	public ResponseEntity<Expense> save(@RequestBody Expense expense) {
		Expense expenseOne = expenseService.save(expense);
		return new ResponseEntity<Expense>(expenseOne, HttpStatus.OK);
	}
	
	@GetMapping("/expenses/{id}")
	public ResponseEntity<Expense> get(@PathVariable("id") Long id) {
		Expense expense = expenseService.findById(id);
		return new ResponseEntity<Expense>(expense, HttpStatus.OK);
	}
	
}

Alright, now we have a rest endpoint to get the single expense, let’s test out work through postman –




Now the rest endpoint is working as we expected, let’s move on to the front end part, and make HTTP GET request from the angular application. let’s begin…

Open, expense.service.ts


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Expense } from '../models/expense';

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

  private getUrl: string = "http://localhost:8080/api/v1/expenses";

  constructor(private _httpClient: HttpClient) { }

  getExpenses(): Observable<Expense[]> {
    return this._httpClient.get<Expense[]>(this.getUrl).pipe(
      map(response => response)
    )
  }

  saveExpense(expense: Expense): Observable<Expense> {
    return this._httpClient.post<Expense>(this.getUrl, expense);
  }

  getExpense(id: number): Observable<Expense> {
    return this._httpClient.get<Expense>(`${this.getUrl}/${id}`).pipe(
      map(response => response)
    )
  }
}

Now we have an angular service method to get single expense by making HTTP GET request to spring boot application, let’s make use of the service method by calling inside the add-expense.component.ts

Open, add-expense.component.ts


import { Component, OnInit } from '@angular/core';
import { Expense } from 'src/app/models/expense';
import { ExpenseService } from 'src/app/services/expense.service';
import { Router, ActivatedRoute } from '@angular/router';

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

  expense: Expense = new Expense();

  constructor(private _expenseService: ExpenseService,
              private _router: Router,
              private _activatedRoute: ActivatedRoute) { }

  ngOnInit(): void {
    const isIdPresent = this._activatedRoute.snapshot.paramMap.has('id');
    if (isIdPresent) {
        const id = +this._activatedRoute.snapshot.paramMap.get('id');
        this._expenseService.getExpense(id).subscribe(
          data => this.expense = data 
        )
    }
  }

  saveExpense() {
    this._expenseService.saveExpense(this.expense).subscribe(
      data => {
        console.log('response', data);
        this._router.navigateByUrl("/expenses");
      }
    )
  }
}

Next, we need to wire up the routerLink inside the list-expense.component.html for the individual expense, to call /editexpense/:id route

Open, list-expense.component.html


<div class="row">
    <div class="col-md-4">
        <a class="btn btn-primary text-light" routerLink="/addexpense">Add Expense</a>
    </div>
</div> 
<div>
    <div class="card mt-1" *ngFor="let expense of expenses">
        <a routerLink="/editexpense/{{expense.id}}" class="card-body flex">
            <span class="text-capitalize font-weight-bold">{{expense.expense}}</span>
            <span class="float-right mr-2 badge badge-pill badge-warning font-weight-bold amount">{{expense.amount | currency: 'INR'}}</span>
        </a>
        
    </div>
</div>

At this point, if you save all the changes and run the application, you will see the following screen –




When the user clicks on any of the expense records, control navigate to the add-expense.component.html in which all the details are auto-filled inside the form –

That’s it now if the user makes any changes/updates to the record, and when they click add expense button that will automatically update the record.

How does it happen? Well, when the user clicks the add expense button, control navigates to the component, from there it will call service method, saveExpense()inside we will make an HTTP POST request to spring boot application. So now the spring boot calls the JpaRepository save() method. This save() works in both ways, meaning if the id available then it will update the record, if the id is not available then it will create new record.




You can find the Github repository here

You can find the step by step video series here




Bushan Sirgur

Hey guys, I am Bushan Sirgur from Banglore, India. Currently, I am working as an Associate project in an IT company.

Leave a Reply