I am creating a project in Angular 13 version. I have used the Angular Bootstrap library to create a list which is sortable and searchable. I have followed the below link to create the list: https://ng-bootstrap.github.io/#/components/table/examples#sortable The code is below:
Service
interface SearchResult {
incomeHeadLists: IncomeHeadInfoModel[];
total: number;
}
interface IncomeHeadListState {
page: number;
pageSize: number;
searchTitle: string;
searchType: string;
searchAmount: number;
searchTotalIncome: number;
sortColumn: string;
sortDirection: SortDirection;
}
const compare = (v1: string | number | boolean, v2: string | number | boolean) => v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
function sort(headLists: IncomeHeadInfoModel[], column: string, direction: string): IncomeHeadInfoModel[] {
if (direction === '' || column === '') {
return headLists;
}
else {
return [...headLists].sort((a: any, b: any) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
@Injectable({
providedIn: 'root'
})
export class IncomeHeadListInfoService {
private apiPATH = 'incomeHead/';
public _search$ = new Subject<void>();
private _incomeHeadLists$ = new BehaviorSubject<IncomeHeadInfoModel[]>([]);
private _total$ = new BehaviorSubject<number>(0);
private _state: IncomeHeadListState = {
page: 1,
pageSize: 5,
searchTitle: '',
searchType: '',
searchAmount: null,
searchTotalIncome: null,
sortColumn: '',
sortDirection: ''
};
constructor(private service: ApplicationService) {
this._search$.pipe(
debounceTime(200),
switchMap(() => this._search()),
delay(200)).subscribe(result => {
this._incomeHeadLists$.next(result.incomeHeadLists);
this._total$.next(result.total);
});
this._search$.next();
}
// getter functions
get incomeHeadLists$() { return this._incomeHeadLists$.asObservable(); }
get total$() { return this._total$.asObservable(); }
get page() { return this._state.page; }
get pageSize() { return this._state.pageSize; }
get searchTitle() { return this._state.searchTitle; }
get searchType() { return this._state.searchType; }
get searchAmount() { return this._state.searchAmount; }
get searchTotalIncome() { return this._state.searchTotalIncome; }
// setter functions
set page(page: number) { this._set({ page }); }
set pageSize(pageSize: number) { this._set({ pageSize }); }
set searchTitle(searchTitle: string) { this._set({ searchTitle }); }
set searchType(searchType: string) { this._set({ searchType }); }
set searchAmount(searchAmount: number) { this._set({ searchAmount }); }
set searchTotalIncome(searchTotalIncome: number) { this._set({ searchTotalIncome }); }
set sortColumn(sortColumn: string) { this._set({ sortColumn }); }
set sortDirection(sortDirection: SortDirection) { this._set({ sortDirection }); }
private _set(patch: Partial<IncomeHeadListState>) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable<SearchResult> {
return this.service.get<IncomeHeadListInfoResultModel>(`${this.apiPATH}lists`).pipe(map(data => {
const {
sortColumn,
sortDirection,
pageSize,
page,
searchTitle,
searchType,
searchAmount,
searchTotalIncome
} = this._state;
if (data) {
let lists = data.IncomeHeads
// 1. sort
let incomeHeadLists = sort(lists, sortColumn, sortDirection);
// 2. filter
if (searchTitle) {
incomeHeadLists = incomeHeadLists.filter(x => x.Title.toLowerCase().includes(searchTitle.toLowerCase()))
}
if (searchType) {
incomeHeadLists = incomeHeadLists.filter(x => x.Type.toLowerCase().includes(searchType.toLowerCase()))
}
if (searchAmount) {
incomeHeadLists = incomeHeadLists.filter(x => x.Amount === searchAmount)
}
if (searchTotalIncome) {
incomeHeadLists = incomeHeadLists.filter(x => x.TotalIncome === searchTotalIncome)
}
const total = incomeHeadLists.length;
// 3. paginate
incomeHeadLists = incomeHeadLists.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return { incomeHeadLists, total };
}
else {
return null;
}
}));
}
}
HTML Component:
<table class="table table-striped table-bordered">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col" sortable="Title" (sort)="onSort($event)">Title</th>
<th scope="col" sortable="Type" (sort)="onSort($event)">Type</th>
<th scope="col" sortable="Amount" (sort)="onSort($event)">Amount</th>
<th scope="col" sortable="TotalIncome" (sort)="onSort($event)">Total Bill</th>
<th scope="col" colspan="2">Action</th>
</tr>
<tr>
<th></th>
<th><input class="form-control" type="text" name="searchTitle" [(ngModel)]="service.searchTitle" /></th>
<th><input class="form-control" type="text" name="searchType" [(ngModel)]="service.searchType" /></th>
<th><input class="form-control" type="text" name="searchAmount" [(ngModel)]="service.searchAmount" /></th>
<th><input class="form-control" type="text" name="searchTotalIncome" [(ngModel)]="service.searchTotalIncome" /></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let incomeHead of incomeHeadLists$ | async; let i = index">
<th scope="row">{{((service.page * service.pageSize) + (i + 1))-service.pageSize}}</th>
<td><ngb-highlight [result]="incomeHead.Title" [term]="service.searchTitle"></ngb-highlight></td>
<td><ngb-highlight [result]="incomeHead.Type" [term]="service.searchType"></ngb-highlight></td>
<td><ngb-highlight [result]="incomeHead.Amount | number" [term]="service.searchAmount"></ngb-highlight></td>
<td><ngb-highlight [result]="incomeHead.TotalIncome | number" [term]="service.searchTotalIncome"></ngb-highlight></td>
<td>
<toogle-button [selectedCheckStatus]="incomeHead.IsActive"
(onChangeCheckStatus)="activeOrInactiveIncomeHead($event, incomeHead, confirmContent)">
</toogle-button>
</td>
<td>
<button type="button" class="btn btn-outline-info"
(click)="editIncomeHead(incomeHead, incomeHeadModalContent)"><i class="fas fa-edit"></i>
</button>
</td>
</tr>
</tbody>
</table>
But I got the below errors:
ERROR
src/app/pages/setup/income-head-list/income-head-list.component.html:32:71
- error TS2322: Type 'number' is not assignable to type 'string | readonly string[]'.
32 <ngb-highlight [result]="incomeHead.Amount | number" [term]="service.searchAmount"> ~~~~
src/app/pages/setup/income-head-list/income-head-list.component.ts:15:15 15 templateUrl: './income-head-list.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error occurs in the template of component IncomeHeadListComponent.
ERROR
src/app/pages/setup/income-head-list/income-head-list.component.html:33:76
- error TS2322: Type 'number' is not assignable to type 'string | readonly string[]'.
33 <ngb-highlight [result]="incomeHead.TotalIncome | number" [term]="service.searchTotalIncome"> ~~~~
src/app/pages/setup/income-head-list/income-head-list.component.ts:15:15 15 templateUrl: './income-head-list.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error occurs in the template of component IncomeHeadListComponent.
The problem is in your "ngb-highlight" ((that need two strings). To convert a number to string simply add ''
at first of the number. You need make it in the two [term]
than mannage number
<td><ngb-highlight [result]="incomeHead.Amount | number"
[term]="''+service.searchAmount">
</ngb-highlight></td>
<td><ngb-highlight [result]="incomeHead.TotalIncome | number"
[term]="''+service.searchTotalIncome">
</ngb-highlight></td>