Top

Tables


you have to install angular bootstrap


 npm i @ng-bootstrap/ng-bootstrapp
# 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 @twitter admin UK
4 Randy Mark Ottandy @mdothe user AUS
5 Ram Jacob Thornton @twitter admin IND
<p>Table is just a mapping of objects to table rows with <code>ngFor</code></p>

<table class="table table-striped">
	<thead>
		<tr>
			<th scope="col">#</th>
			<th scope="col">Country</th>
			<th scope="col">Area</th>
			<th scope="col">Population</th>
		</tr>
	</thead>
	<tbody>
  @for( country of countries; track country; let i = $index){
		<tr>
			<th scope="row">{{ i + 1 }}</th>
			<td>
				<img
					[src]="'https://upload.wikimedia.org/wikipedia/commons/' + country.flag"
					class="me-2"
					style="width: 20px"
				/>
				{{ country.name }}
			</td>
			<td>{{ country.area | number }}</td>
			<td>{{ country.population | number }}</td>
		</tr>
  }
	</tbody>
</table>
To use Bootstrap basic table you have to add the following type script
import { Component } from '@angular/core';
import { DecimalPipe, NgFor } from '@angular/common';

interface Country {
	name: string;
	flag: string;
	area: number;
	population: number;
}

const COUNTRIES: Country[] = [
	{
		name: 'Russia',
		flag: 'f/f3/Flag_of_Russia.svg',
		area: 17075200,
		population: 146989754,
	},
	{
		name: 'Canada',
		flag: 'c/cf/Flag_of_Canada.svg',
		area: 9976140,
		population: 36624199,
	},
	{
		name: 'United States',
		flag: 'a/a4/Flag_of_the_United_States.svg',
		area: 9629091,
		population: 324459463,
	},
	{
		name: 'China',
		flag: 'f/fa/Flag_of_the_People%27s_Republic_of_China.svg',
		area: 9596960,
		population: 1409517397,
	},
];

@Component({
	selector: 'ngbd-table-basic',
	imports: [NgFor, DecimalPipe],
	templateUrl: './table-basic.html',
  styleUrls: ['./table-basic.scss']
})
export class NgbdTableBasic {
	countries = COUNTRIES;
}

You have to change only table sizing class.you can use table-*(sm,lg,xl,xs) class

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table table-lg">
           <thead>
              <tr>
               <th scope="col">Id</th>
               <th scope="col">Employee Name</th>
               <th scope="col">Date</th>
               <th scope="col">Status</th>
               <th scope="col">Hours</th>
               <th scope="col">Performance</th>
              </tr>
         </thead>
       <tbody>
          @for(table of sizingData;track table){
             <tr>
              <th scope="row">{{table.id}}</th>
              <td>{{table.name}}</td>
              <td>{{table.date}}</td>
              <td class="font-{{table.class}}">{{table.text}}</td>
              <td>{{table.performance}}</td>
              <td>{{table.hours}}</td>
             </tr>
           }
       </tbody>
  </table>
To use Sizing table you have to add the following type script
import { Component } from '@angular/core';

@Component({
  selector: 'app-sizing-tables',
  imports: [],
  templateUrl: './sizing-tables.html',
  styleUrls: ['./sizing-tables.scss']
})
export class SizingTables {

  export const sizingTable = [
  {
    id: 1,
    name: 'Mark Jecno',
    date: '22/08/2023',
    class: 'danger',
    text: 'on leave',
    hours: 0,
    performance: '29/30'
     },
    {
    id: 2,
    name: 'Elana Robbert',
    date: '21/08/2023',
    class: 'success',
    text: 'Present',
    hours: 10,
    performance: '30/30'
     },
    {
    id: 3,
    name: 'John Deo',
    date: '18/08/2023',
    class: 'danger',
    text: 'on leave',
    hours: 8,
    performance: '28/30'
     },
   ]
 

}


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
<form>
  <div class="mb-3 row">
    <label for="table-complete-search" class="col-xs-3 col-sm-auto col-form-label">Full text 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>
  </div>
  <table class="table table-striped">
    <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; track data ){
      <tr>
        <th scope="row">{{data.id}}</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" (click)="deleteData(data.id)"></i>
          </ul>
        </td>
      </tr>
    }
    @empty{
      <tr class="odd">
        <td colspan="8" class="dataTables_empty" style="text-align: center;">No records found</td>
      </tr>
      }
      @if(service.loading$ | async){
        <span class="col col-form-label">Loading...</span>
      }
    </tbody>
  </table>
  <div class="d-flex justify-content-between p-2">
    <select class="form-select" style="width: auto" name="pageSize" [(ngModel)]="service.pageSize">
      <option [ngValue]="2">2 items per page</option>
      <option [ngValue]="4">4 items per page</option>
      <option [ngValue]="6">6 items per page</option>
      <option [ngValue]="10">10 items per page</option>
    </select>
    <ngb-pagination class="ms-3" [collectionSize]="( total$ | async)!" [(page)]="service.page"
      [pageSize]="service.pageSize">
    </ngb-pagination>
  </div>
</form>
To use datatable you have to add the following type script fills

  import { CommonModule, DecimalPipe } from '@angular/common';
import { Component, inject, viewChildren } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { NgbPaginationModule, NgbTypeaheadModule } 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/table.service';

@Component({
  selector: 'app-data-table',
  imports: [
    CommonModule,
    FormsModule,
    NgbdSortableHeaderDirective,
    NgbPaginationModule,
    NgbTypeaheadModule,
  ],
  templateUrl: './data-table.html',
  styleUrls: ['./data-table.scss'],
  providers: [TableService, DecimalPipe],
})
export class DataTable {
  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;
  }

  deleteData(id: number) {
    this.tableData$.subscribe((data: supportDB[]) => {
      data.map((elem: supportDB) => {
        elem.id == id && data.splice(id, 1);
      });
    });
  }
}

you have use this services fill

  import { DecimalPipe } from '@angular/common';
  import { inject, Injectable, PipeTransform } from '@angular/core';
  
  import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
  import { debounceTime, delay, switchMap, tap } from 'rxjs/operators';
  
  import { SUPPORTDB } from '../../data/component/table/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, pipe: PipeTransform) {
    return (
      support.name.toLowerCase().includes(term.toLowerCase()) ||
      support.position.toLowerCase().includes(term.toLowerCase()) ||
      pipe.transform(support.salary).includes(term) ||
      support.office.toLowerCase().includes(term.toLowerCase()) ||
      pipe.transform(support.extn).includes(term) ||
      support.email.toLowerCase().includes(term.toLowerCase())
    );
  }
  
  @Injectable({ providedIn: 'root' })
  export class TableService {
    private 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: 4,
      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, this.pipe));
      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, input, output, signal, HostBinding, HostListener } 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({
  selector: 'th[sortable]',
  standalone: true,
})
export class NgbdSortableHeaderDirective {
  // Read-only input signal
  readonly sortable = input('');
  readonly direction = input(''); // initial direction from parent

  // Writable signal for local state
  public currentDirection = signal(this.direction());

  // Output event
  readonly sort = output();

  // HostBinding to update CSS classes dynamically
  @HostBinding('class.asc')
  get isAsc() {
    return this.currentDirection() === 'asc';
  }

  @HostBinding('class.desc')
  get isDesc() {
    return this.currentDirection() === 'desc';
  }

  // HostListener to handle clicks
  @HostListener('click')
  rotateColumn() {
    this.currentDirection.set(rotate[this.currentDirection()]);
    this.sort.emit({ column: this.sortable(), direction: this.currentDirection() });
  }
}