Tables
Bootstrap basic table Preview link
| # | First Name | Last Name | Username | Role | Country |
|---|---|---|---|---|---|
| 1 | Alexander | Orton | @mdorton | Admin | USA |
| 2 | John Deo | Deo | @johndeo | User | USA |
| 3 | Randy Orton | the Bird | admin | UK | |
| 4 | Randy Mark | Ottandy | @mdothe | user | AUS |
| 5 | Ram Jacob | Thornton | admin | IND |
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">First Name</th>
<th scope="col">Last Name</th>
<th scope="col">Username</th>
<th scope="col">Role</th>
<th scope="col">Country</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Alexander</td>
<td>Orton</td>
<td>@mdorton</td>
<td>Admin</td>
<td>USA</td>
</tr>
<tr>
<th scope="row">2</th>
<td>John Deo</td>
<td>Deo</td>
<td>@johndeo</td>
<td>User</td>
<td>USA</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Randy Orton</td>
<td>the Bird</td>
<td>@twitter</td>
<td>admin</td>
<td>UK</td>
</tr>
<tr>
<th scope="row">4</th>
<td>Randy Mark</td>
<td>Ottandy</td>
<td>@mdothe</td>
<td>user</td>
<td>AUS</td>
</tr>
<tr>
<th scope="row">5</th>
<td>Ram Jacob</td>
<td>Thornton</td>
<td>@twitter</td>
<td>admin</td>
<td>IND</td>
</tr>
</tbody>
</table>
</div>
Datatable Offical link Preview link
| Name | Position | Office | Age | Start date | Salary |
|---|---|---|---|---|---|
| Tiger Nixon | System Architect | Edinburgh | 61 | 2011/04/25 | $320,800 |
| Garrett Winters | Accountant | Tokyo | 63 | 2011/07/25 | $170,750 |
<div class="card">
<form class="table-responsive theme-scroollbar">
<div class="card-body">
<div class="card-header">
<h3>Individual column searching (text inputs) </h3><span>The searching functionality provided by
DataTables is useful for quickly search through the information in the table - however the search is
global,
and you may wish to present controls that search on specific columns.</span>
</div>
<div class="dataTables_wrapper">
<div class="d-flex justify-content-between p-2">
<div class="dataTables_length" id="basic-6_length">
<label>Show
<select name="pageSize" [(ngModel)]="service.pageSize">
<option [ngValue]="10">10</option>
<option [ngValue]="15">15</option>
<option [ngValue]="20">20</option>
<option [ngValue]="25">25</option>
</select> entries
</label>
</div>
<div class="mb-3 row">
<label for="table-complete-search" class="col-xs-3 col-sm-auto col-form-label">Search:</label>
<div class="col-xs-3 col-sm-auto">
<input id="table-complete-search" type="text" class="form-control" name="searchTerm"
[(ngModel)]="service.searchTerm" autocomplete="off" />
</div>
@if(service.loading$ | async){
<span class="col col-form-label">Loading...</span>
}
</div>
</div>
<table class="display table table-striped table-hover table-light">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
<th scope="col" sortable="position" (sort)="onSort($event)">Position</th>
<th scope="col" sortable="salary" (sort)="onSort($event)">Salary</th>
<th scope="col" sortable="office" (sort)="onSort($event)">Office</th>
<th scope="col" sortable="extn" (sort)="onSort($event)">Extn</th>
<th scope="col" sortable="email" (sort)="onSort($event)">Email</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
@for(data of tableData$ | async; track data; let i = $index){
<tr>
<th scope="row">{{ i + 1 + ((service.page - 1) * service.pageSize)}}</th>
<td>
<ngb-highlight [result]="data.name" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="data.position" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="data.salary|number"
[term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="data.office" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="data.extn|number" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="data.email" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ul class="action">
<i class="fa fa-eye font-primary pe-2"></i>
<i class="icofont icofont-close-circled font-danger ps-2"></i>
</ul>
</td>
</tr>
}
@empty{
<tr class="odd">
<td colspan="10" class="dataTables_empty" style="text-align: center;">
<div class="search-not-found text-center">
<p>Sorry, No records found</p>
</div>
</td>
</tr>
}
</tbody>
</table>
<div class="d-flex justify-content-between p-2">
<div class="dataTables_info">
<span class="mt-4">Showing {{ getStartingIndex() }} to {{ getEndingIndex() }} of {{
filteredData.length }} entries</span>
</div>
<ngb-pagination class="ms-3" [collectionSize]="( total$ | async)!" [(page)]="service.page"
[pageSize]="service.pageSize">
</ngb-pagination>
</div>
</div>
</div>
</form>
</div>
To use datatable you have to add code .ts file fills
import { CommonModule, DecimalPipe } from '@angular/common';
import { Component, inject, viewChildren } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import {
NgbdSortableHeaderDirective,
SortEvent,
} from '../../../shared/directives/sortable.directive';
import { supportDB } from '../../../shared/interface/support';
import { TableService } from '../../../shared/services/table.service';
@Component({
selector: 'app-data-table',
imports: [CommonModule, FormsModule, NgbdSortableHeaderDirective, ReactiveFormsModule, NgbModule],
templateUrl: './data-table.html',
styleUrl: './data-table.scss',
providers: [TableService, DecimalPipe],
})
export class DataTables {
public service = inject(TableService);
public tableData$: Observable = this.service.supportdata$;
public total$: Observable = this.service.total$;
public Data: supportDB[];
readonly headers = viewChildren(NgbdSortableHeaderDirective);
ngOnInit() {
this.tableData$.subscribe(res => {
this.Data = res;
});
}
onSort({ column, direction }: SortEvent) {
this.headers().forEach(header => {
if (header.sortable() !== column) {
header.currentDirection.set('');
}
});
this.service.sortColumn = column;
this.service.sortDirection = direction;
}
}
you have use this services fill
import { DecimalPipe } from '@angular/common';
import { inject, Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import { debounceTime, delay, switchMap, tap } from 'rxjs/operators';
import { SUPPORTDB } from '../../shared/data/table/SupportTdb';
import { SortColumn, SortDirection } from '../directives/sortable.directive';
import { supportDB } from '../interface/support';
interface SearchResult {
Details: supportDB[];
total: number;
}
interface State {
page: number;
pageSize: number;
searchTerm: string;
sortColumn: SortColumn;
sortDirection: SortDirection;
}
const compare = (v1: string | number, v2: string | number) => (v1 < v2 ? -1 : v1 > v2 ? 1 : 0);
function sort(countries: supportDB[], column: SortColumn, direction: string): supportDB[] {
if (direction === '' || column === '') {
return countries;
} else {
return [...countries].sort((a, b) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
function matches(support: supportDB, term: string) {
return (
support.name.toLowerCase().includes(term.toLowerCase()) ||
support.position.toLowerCase().includes(term.toLowerCase()) ||
support.office.toLowerCase().includes(term.toLowerCase()) ||
support.email.toLowerCase().includes(term.toLowerCase())
);
}
@Injectable({ providedIn: 'root' })
export class TableService {
public pipe = inject(DecimalPipe);
private _loading$ = new BehaviorSubject(true);
private _search$ = new Subject();
private _data$ = new BehaviorSubject([]);
private _total$ = new BehaviorSubject(0);
private _state: State = {
page: 1,
pageSize: 10,
searchTerm: '',
sortColumn: '',
sortDirection: '',
};
constructor() {
this._search$
.pipe(
tap(() => this._loading$.next(true)),
debounceTime(200),
switchMap(() => this._search()),
delay(200),
tap(() => this._loading$.next(false)),
)
.subscribe(result => {
this._data$.next(result.Details);
this._total$.next(result.total);
});
this._search$.next();
}
get supportdata$() {
return this._data$.asObservable();
}
get total$() {
return this._total$.asObservable();
}
get loading$() {
return this._loading$.asObservable();
}
get page() {
return this._state.page;
}
get pageSize() {
return this._state.pageSize;
}
get searchTerm() {
return this._state.searchTerm;
}
set page(page: number) {
this._set({ page });
}
set pageSize(pageSize: number) {
this._set({ pageSize });
}
set searchTerm(searchTerm: string) {
this._set({ searchTerm });
}
set sortColumn(sortColumn: SortColumn) {
this._set({ sortColumn });
}
set sortDirection(sortDirection: SortDirection) {
this._set({ sortDirection });
}
private _set(patch: Partial) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable {
const { sortColumn, sortDirection, pageSize, page, searchTerm } = this._state;
// 1. sort
let Details = sort(SUPPORTDB, sortColumn, sortDirection);
// 2. filter
Details = Details.filter(support => matches(support, searchTerm));
const total = Details.length;
// 3. paginate
Details = Details.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({ Details, total });
}
}
you have use this directive
import { Directive, HostBinding, HostListener, input, output, signal } from '@angular/core';
import { supportDB } from '../interface/support';
export type SortColumn = keyof supportDB | '';
export type SortDirection = 'asc' | 'desc' | '';
const rotate: { [key: string]: SortDirection } = { asc: 'desc', desc: '', '': 'asc' };
export interface SortEvent {
column: SortColumn;
direction: SortDirection;
}
@Directive({
standalone: true,
selector: 'th[sortable]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()',
},
})
export class NgbdSortableHeaderDirective {
readonly sortable = input('');
readonly direction = input('');
public currentDirection = signal(this.direction());
// Output event
readonly sort = output();
@HostBinding('class.asc')
get isAsc() {
return this.currentDirection() === 'asc';
}
@HostBinding('class.desc')
get isDesc() {
return this.currentDirection() === 'desc';
}
@HostListener('click')
rotateColumn() {
this.currentDirection.set(rotate[this.currentDirection()]);
this.sort.emit({ column: this.sortable(), direction: this.currentDirection() });
}
}
import { Directive, HostBinding, HostListener, input, output, signal } from '@angular/core';
import { supportDB } from '../interface/support';
export type SortColumn = keyof supportDB | '';
export type SortDirection = 'asc' | 'desc' | '';
const rotate: { [key: string]: SortDirection } = { asc: 'desc', desc: '', '': 'asc' };
export interface SortEvent {
column: SortColumn;
direction: SortDirection;
}
@Directive({
standalone: true,
selector: 'th[sortable]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()',
},
})
export class NgbdSortableHeaderDirective {
readonly sortable = input('');
readonly direction = input('');
public currentDirection = signal(this.direction());
// Output event
readonly sort = output();
@HostBinding('class.asc')
get isAsc() {
return this.currentDirection() === 'asc';
}
@HostBinding('class.desc')
get isDesc() {
return this.currentDirection() === 'desc';
}
@HostListener('click')
rotateColumn() {
this.currentDirection.set(rotate[this.currentDirection()]);
this.sort.emit({ column: this.sortable(), direction: this.currentDirection() });
}
}