Introduction

In this tutorial we will see how to delete multiple rows from HTML table as well as from database server at one go. We have seen tutorial how to display data from server to client side and how to select multiple rows on HTML table.

We will put checkbox against each row on the table so that user will be able to select a particular row for deletion. We will also put a checkbox on the table header and selecting this checkbox all rows on the table will be selected for deletion.

If user selects manually all checkboxes for rows on the table then the checkbox in table header will be checked automatically to show that all checkboxes on the table body are checked. If any of the checkboxes on the table body gets unchecked the header checkbox will be unchecked automatically.

Prerequisites

Angular 9, CSS, HTML, REST API Endpoints – /products and /delete/products

How to Create Angular Project

To update Angular 9, execute command ng update on project’s root directory.

Model Class

We will map JSON object from the server into client side object. The class file product.ts is created under src/app folder.

Therefore we are creating a class called Product which has below attributes:

export class Product {
  id?: number;
  name: string;
  code: string;
  price: number;
  checked?: boolean;
}

The class is straight forward and notice ?, which indicates optional value for id and checked fields.

Generally ? is not required on id field when you are fetching data from server but may be required when you want to save data if you are generating id value on server side.

The checked field indicates whether a particular checkbox is checked/selected or not.

Service Class

Service class is required to process your business logic. The class file product.service.ts is created under src/app folder.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of } from 'rxjs';
//import { catchError, map, tap } from 'rxjs/operators';
import { Product } from './product';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable({ providedIn: 'root' })
export class ProductService {
  private productUrl = 'http://localhost:8080';  // URL to REST API
  
  constructor(private http: HttpClient) { }
  
  /** GET products from the server */
  getProducts(): Observable<Product[]> {
    return this.http.get<Product[]>(this.productUrl + '/products');
  }
  
  /** DELETE: delete the product from the server */
  deleteProducts(ids: number[]) {
	  if (confirm("Are you sure to delete?")) {
		const data = {'ids' : ids};
		const url = `${this.productUrl}/delete/products`;
		const options = {
			headers: new HttpHeaders({
				'Accept': 'application/json',
				'Content-Type': 'application/json'
			}),
			responseType: 'text' as 'json'
		};
		
		const resp = this.http.post<any>(url, data, options);//.map(resp => {return resp;}).catch(err => {console.log(err);});
		
		//console.log('resp: ' + resp);
		
		return resp;
	  }
	  
	  return of({});
  }
}

Notice we have used @Injectable({ providedIn: 'root' }) to make the service class singleton.

A singleton service is a service for which only one instance exists in an app.

There are two ways to make a service a singleton in Angular:

  • Set the providedIn property of the @Injectable() to “root”.
  • Include the service in the AppModule or in a module that is only imported by the AppModule (explained later).

We have defined two functions – one for fetching data from server and another one for deleting data from the server. For delete also we are using HTTP method POST because we want to pass multiple product ids to delete products from the MySQL database.

Change Page Title Globally

We will replace the title in the file src/index.html with the below title:

<title>Delete Multiple Table Rows from Server using Angular</title>

If you want to change title for specific title then you have set in the corresponding *.component.ts file.

Load Required Module Globally

We need to import required modules, such as, HttpClientModule and FormsModule into the file src/app/app.module.ts file.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule }    from '@angular/common/http';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
	FormsModule,
    BrowserModule,
	HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We discussed about making service class singleton and we could have included the ProductService class into the above file inside provides: [], such as, providers: [ProductService].

Load/Delete Data – Component

In order to display data on HTML file we need to load data into corresponding component TypeScript file. So here we have only app component, so we are going to use app.component.ts file under src/app directory.

We have also created to check individual or all checkbox are checked/selected or not.

We have defined function to delete the selected products from the HTML table.

import { Component, OnInit } from '@angular/core';

import { Product } from './product';
import { ProductService } from './product.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
	msg: string;
	clss: string;
	products: Product[] = [];
	
	constructor(private productService: ProductService) { }
	
	ngOnInit() {
		this.getProducts();
	}
	
	getProducts(): void {
		this.productService.getProducts().subscribe(products => this.products = products);
	}
	
	checkAllCheckBox(ev) {
		this.products.forEach(x => x.checked = ev.target.checked)
	}

	isAllCheckBoxChecked() {
		return this.products.every(p => p.checked);
	}
	
	deleteProducts(): void {
		const selectedProducts = this.products.filter(product => product.checked).map(p => p.id);
		//console.log (selectedProducts);
		
		if(selectedProducts && selectedProducts.length > 0) {
			this.productService.deleteProducts(selectedProducts)
				.subscribe(res => {
					this.clss = 'grn';
					this.msg = 'Products successfully deleted';
					}, err => {
                        this.clss = 'rd';
						this.msg = 'Something went wrong during deleting products';
                    }
                );
		} else {
			this.clss = 'rd';
			this.msg = 'You must select at least one product';
		}
	}
}

Display Data on HTML Table

Now we will display data on HTML table and provide the checkbox to check/select rows on HTML table for deletion.

We have put a button above the table to delete the selected products. If you do not select any row from the table then you will see error message.

We have put two <div/>s to display messages – error and success. Error message is shown in red color while success message is shown in green color.

<h1>Delete Multiple Table Rows from Server using Angular</h1>

<div *ngIf="products && products.length > 0; else elseBlock">
	<div *ngIf="msg" [ngClass]="clss">{{msg}}</div>
	<div *ngIf="errMsg" [ngClass]="clss">{{errMsg}}</div>
	<button type="button" (click)="deleteProducts()">Delete Selected Product(s)</button>
	<table class="datatable">
		<thead>
			<tr>
				<th><input type="checkbox" [checked]="isAllCheckBoxChecked()" (change)="checkAllCheckBox($event)"></th>
				<th>ID</th>
				<th>Code</th>
				<th>Name</th>
				<th>Price</th>
			</tr>
		</thead>
		<tbody>
			<tr *ngFor="let p of products; let i=index; let odd = odd" [ngClass]="odd ? 'odd_col' : 'even_col'">
				<td><input type="checkbox" value="{{p.id}}" [(ngModel)]="products[i].checked"></td>
				<td>{{ p.id }}</td>
				<td>{{ p.name }}</td>
				<td>{{ p.code }}</td>
				<td>{{ p.price }}</td>
			</tr>
		</tbody>
	</table>
</div>
<ng-template #elseBlock><div style="color: red;">No record found</div></ng-template>

Apply Style

Apply basic style on table and two different colors for alternate rows.

We have also applied the color to the error and success message <div/>s.

table.datatable {
	width:100%;
	border: none;
	background:#fff;
}
table.datatable td.table_foot {
	border: none;
	background: #fff;
	text-align: center;
}
table.datatable tr.odd_col {
	background: none;
}
table.datatable tr.even_col {
	background: #ddd;
}
table.datatable td {
	font-size:10pt;
	padding:5px 10px;
	text-align: left;
}
table.datatable th {
	text-align: left;
	font-size: 8pt;
	padding: 10px 10px 7px;   
	text-transform: uppercase;
	color: #fff;
	background-color: black;
	font-family: sans-serif;
}

.rd {
	color: red;
}

.grn {
	color: green;
}

Testing the Application

Finally execute the command ng serve --open on project’s root directory to run the application and the application opens up automatically in the browser at http://localhost:4200.

The below youtube video shows how it works.

Source Code

Download

Thanks for reading.

Tags:

Leave a Reply

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