<table class="table display" id="selling-product" style="width:100%">
<thead>
<tr>
<th>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="">
<label class="form-check-label" for="flexCheckDefault"></label>
</div>
</th>
<th scope="col">#UID</th>
<th scope="col" sortable="product" (sort)="onSort($event)" style="cursor: pointer;">Product</th>
<th scope="col" sortable="category" (sort)="onSort($event)" style="cursor: pointer;">Catagory</th>
<th scope="col" sortable="brand" (sort)="onSort($event)" style="cursor: pointer;">Brand</th>
<th scope="col" sortable="price" (sort)="onSort($event)" style="cursor: pointer;">Price </th>
<th scope="col" sortable="stock" (sort)="onSort($event)" style="cursor: pointer;">Stock</th>
<th scope="col" sortable="rating" (sort)="onSort($event)" style="cursor: pointer;">Rating</th>
<th scope="col" sortable="order" (sort)="onSort($event)" style="cursor: pointer;">Order</th>
<th scope="col" sortable="sales" (sort)="onSort($event)" style="cursor: pointer;">Sales</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of selling$ | async; let i=index">
<td>
<div class="form-check">
<input class="form-check-input" id="flexCheckDefault" type="checkbox" value="">
<label class="form-check-label" for="flexCheckDefault"></label>
</div>
</td>
<td><b>#{{data.id}}</b></td>
<td>
<div class="d-flex align-items-center">
<div class="flex-shrink-0"><img class="img-50" src={{data.img}}>
</div>
<div class="flex-grow-1 ms-2"><a
[routerLink]="['/ecommerce/product-page']">
<h5>{{data.product}}</h5>
</a></div>
</div>
</td>
<td><b>{{data.category}}</b></td>
<td><b>{{data.brand}}</b></td>
<td><b>${{data.price | number : '1.2-2'}}</b></td>
<td><b>{{data.stock}}</b></td>
<td><b>
<p><i class="fa fa-star font-warning"></i>{{data.rating}}</p>
</b></td>
<td><b>{{data.order}}</b></td>
<td><b>{{data.sales}}</b></td>
<td class="text-center">
<span class="edit-option">
<a href="javascript:void(0)">
<app-feather-icons [icon]="'edit'"></app-feather-icons>
<!-- <i data-feather="edit"></i> -->
</a>
</span>
<span class="delete-option">
<a href="javascript:void(0)" (click)="removeItem(data.id)">
<i class="remove" data-feather="trash-2"></i>
</a>
</span>
</td>
</tr>
</tbody>
</table>
import { Component, QueryList, ViewChildren } from '@angular/core';
import { Observable } from 'rxjs';
import { sellingProduct } from '../../../../shared/data/data/default-dashboard/best-selling-product';
import { SortEvent, SortableDirective } from '../../../../shared/directive/sortable.directive';
import { TablesService } from '../../../../shared/services/tables/tables.service';
import { FeatherIcons } from '../../../../shared/component/feather-icons/feather-icons';
import { RouterLink } from '@angular/router';
import { AsyncPipe, DecimalPipe } from '@angular/common';
@Component({
selector: 'app-common-data-table',
templateUrl: './common-data-table.html',
styleUrls: ['./common-data-table.scss'],
imports: [SortableDirective, RouterLink, FeatherIcons, AsyncPipe, DecimalPipe]
})
export class CommonDataTable {
public isShow : boolean = false;
public selling$ : Observable;
public total$ : Observable;
@ViewChildren(SortableDirective) headers!: QueryList;
constructor(public service : TablesService) {
this.selling$ = service.selling$;
this.total$ = service.total$;
}
onSort({ column, direction }: SortEvent){
this.headers.forEach((header) => {
if(header.sortable !== column) {
header.direction = '';
}
});
this.service.sortColumn = column;
this.service.sortDirection = direction;
}
removeItem(id: number){
this.selling$.subscribe((data: sellingProduct[])=> {
data.map((elem: sellingProduct,i: number)=>{elem.id == id && data.splice(i,1)})
})
}
}
import { Injectable, PipeTransform } from '@angular/core';
import { BehaviorSubject, Observable, Subject, debounceTime, delay, of, pipe, switchMap, tap } from 'rxjs';
import { DecimalPipe } from '@angular/common';
import { SortColumn, SortDirection } from '../../directive/sortable.directive';
import { BestSellingProduct, sellingProduct } from '../../data/data/default-dashboard/best-selling-product';
interface SearchResult {
selling: sellingProduct[];
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(selling: sellingProduct[], column: SortColumn, direction: string): sellingProduct[] {
if (direction === '' || column === '') {
return selling;
} else {
return [...selling].sort((a : any, b : any) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
function matches(sellingData: sellingProduct, term: string, pipe: PipeTransform) {
return (
sellingData.product.toLowerCase().includes(term.toLowerCase()) ||
sellingData.category.toLowerCase().includes(term.toLowerCase()) ||
sellingData.brand.toLowerCase().includes(term.toLowerCase()) ||
pipe.transform(sellingData.price).includes(term) ||
pipe.transform(sellingData.stock).includes(term) ||
pipe.transform(sellingData.order).includes(term) ||
pipe.transform(sellingData.sales).includes(term)
);
}
@Injectable({
providedIn: 'root'
})
export class TablesService {
private _loading$ = new BehaviorSubject(true);
private _search$ = new Subject();
private _selling$ = new BehaviorSubject([]);
private _total$ = new BehaviorSubject(0);
private _state: State = {
page: 1,
pageSize: 4,
searchTerm: '',
sortColumn: '',
sortDirection: '',
};
constructor(private pipe: DecimalPipe) {
this._search$
.pipe(
tap(() => this._loading$.next(true)),
debounceTime(200),
switchMap(() => this._search()),
delay(200),
tap(() => this._loading$.next(false)),
)
.subscribe((result) => {
this._selling$.next(result.selling);
this._total$.next(result.total);
});
this._search$.next();
}
get selling$() {
return this._selling$.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 selling = sort(BestSellingProduct, sortColumn, sortDirection);
// 2. filter
selling = selling.filter((sellingProduct) => matches(sellingProduct, searchTerm, this.pipe));
const total = selling.length;
// 3. paginate
selling = selling.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({ selling, total });
}
}
import { Directive, EventEmitter, Input, Output } from '@angular/core';
import { sellingProduct } from '../data/data/default-dashboard/best-selling-product';
export type SortColumn = keyof sellingProduct | '';
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]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()',
},
})
export class SortableDirective {
@Input() sortable: SortColumn = '';
@Input() direction: SortDirection = '';
@Output() sort = new EventEmitter();
rotate() {
this.direction = rotate[this.direction];
this.sort.emit({ column: this.sortable, direction: this.direction });
}
constructor() { }
}