You are currently viewing Angular 9 and Spring Boot CRUD Tutorial – Feature 4 Delete expense details

Angular 9 and Spring Boot CRUD Tutorial – Feature 4 Delete expense details

Hey everyone, in the previous post we discussed updating the expense details, and in this post, we will discuss deleting an expense. we can delete expense from two different places, one is in the list expense page, where each expense contains the delete button/link and another place inside the add expense page while editing the expense. Let’s add this to both the places…




We will cover the following topics –

  • First, we will create a rest endpoint to delete an expense
  • Next, we will make delete request to rest endpoint from angular application

First, let’s declare a new method inside the ExpenseService.java to delete an expense

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);
	
	void delete(Long id);
}

Now let’s provide an implementation for deleting an expense inside the ExpenseServiceImpl.java

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;
	}

	@Override
	public void delete(Long id) {
		Expense expense = findById(id);
		expenseRepository.delete(expense);
	}

}

Now we have a service method for deleting an expense, all we need to do is call this service method inside the 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);
	}
	
	@DeleteMapping("/expenses/{id}")
	public ResponseEntity<String> delete(@PathVariable("id") Long id) {
		expenseService.delete(id);
		return new ResponseEntity<String>("Expense is deleted successfully.!", HttpStatus.OK);
	}
}

Alright, now we have a rest endpoint to delete an expense, all we need to do is test our work –




Now let’s move on to the front end part – let’s utilize this rest endpoint to make HTTP delete request for deleting an expense

Open expense.service.ts, add the following code –

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)
    )
  }

  deleteExpense(id: number): Observable<any> {
    return this._httpClient.delete(`${this.getUrl}/${id}`, {responseType: 'text'});
  }
}

Now let’s call this service method inside the component, so as we discussed earlier we will delete expense from 2 different places, first let’s add inside the list expenses page.

Open list-expenses.component.ts, add the following code

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


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

  expenses: Expense[] = [];

  constructor(private _expenseService: ExpenseService) { }

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

  deleteExpense(id: number) {
    this._expenseService.deleteExpense(id).subscribe(
      data => {
        console.log('deleted response', data);
        this.listExpenses();
      }
    )
  }

  listExpenses() {
    this._expenseService.getExpenses().subscribe(
      data => this.expenses = data
    )
  }
}

Now, let’s add delete button/link inside the list-expenses.component.html view template

<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 class="card-footer">
            <button class="btn btn-danger" (click)="deleteExpense(expense.id)" style="width: 10%;">Delete</button>
        </div>
    </div>
</div>

At this, if you run the application, you will see the following output –




Now let’s add the same functionality inside the add-expense.component.ts file

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");
      }
    )
  }

  deleteExpense(id: number) {
    this._expenseService.deleteExpense(id).subscribe(
      data => {
        console.log('deleted response', data);
        this._router.navigateByUrl('/expenses');
      }
    )
  }

}

Now we need to add the delete button/link inside the add-expense.component.html view template




<div class="container">
        <div class="row">
                <form (ngSubmit)="saveExpense()">

                        <div class="form-group">
                                <input type="text" name="expense" [(ngModel)]="expense.expense"
                                placeholder="Enter expense name" class="form-control col-md-12 "/>
                        </div>

                        <div class="form-group">
                                <input type="text" name="amount" [(ngModel)]="expense.amount" placeholder="Enter amount" 
                                class="form-control col-md-12" />
                        </div>

                        <div class="form-group">
                                <textarea type="text" name="description" [(ngModel)]="expense.description"
                                placeholder="Enter description" class="form-control col-md-12"></textarea>
                        </div>

                        <button type="submit" class="btn btn-primary">Add Expense</button>
                        <button *ngIf="expense.id" (click)="deleteExpense(expense.id)" class="btn btn-danger">Delete</button>

                </form>
        </div>
</div>

At this point, if you run the application, you will see the following output –

That’s it for this post, in the next post we will look at the search operation.




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