Hello, I am a beginner in Angular and need some help with implementing sorting functionality. I have an input class called Foo which contains a list of books with properties like Id, Title, and Description. These books are displayed in a table where users can add, edit, or delete them. The feature to add and delete books is working correctly.
However, when I tried to add sorting using MatSort and Sort from Angular itself, it didn't work as expected. I'm not sure what I'm doing wrong. Should I switch to using MatTable instead of looping through a form array to achieve sorting? And if yes, how can I implement this with inputs instead of displaying data variables like {{element.title}}?
I appreciate any assistance on this matter.
Thank you!
@Input() foo: Foo;
@ViewChild(MatSort, {static: true}) sort: MatSort;
bookForm: FormArray;
orderForm: FormGroup;
bookList !: Book[];
bookSorted : Book[];
initForm() {
this.orderForm= this._formBuilder.group( {
customerForm: this._formBuilder.array( [] ),
bookForm: this._formBuilder.array( [] )
} );
this.addedBooks()
this.bookList = this.foo.Books;
}
addedBooks() {
this.bookForm= this.orderForm.get( 'bookForm' ) as FormArray;
this.bookForm.clear();
let _bookForm = this.foo.books?.map( _book => this.addBook( _book ) );
_bookForm?.forEach( _addBook => this.bookForm.push( _addBook ) );
}
addBook( _book) {
return this._formBuilder.group( {
title: new FormControl( _book?.title),
description: new FormControl( _book?.description ),
id: new FormControl( _book?.id ?? Guid.EMPTY ),
} );
}
get bookFormControls {
return ( this.orderForm.get( 'bookForm' ) as FormArray ).controls;
}
sortBook(sort: Sort) {
const data = this.bookList.slice();
if (!sort.active || sort.direction == '') {
this.bookSorted = data;
return;
}
this.bookSorted = data.sort((a, b) => {
let isAsc = sort.direction == 'asc';
switch (sort.active) {
case 'title': return this.compare(a.title, b.title, isAsc);
case 'description': return this.compare(+a.description, +b.description, isAsc);
default: return 0;
}
});
}
compare(a, b, isAsc) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
removeBooksAt( index ) {
this.dialogName = "Book"
this.modalRef = this.dialog.open( this.deleteBook, {
width: '600px',
} );
this.modalRef.afterClosed().subscribe( res => {
if ( res ) this.bookForm.removeAt( index );
} );
}
addNewBook() {
let formValue = this.orderForm.controls['bookForm'] as FormArray;
formValue.status == 'VALID' ? this.createBooksForm() : this.showToast();
}
createBooksForm(data?: any) {
this.booksForm = this.orderForm.get( 'booksForm ' ) as FormArray;
this.booksForm .push( this.addBooksControls(data) );
}
addBooksControls(data?: any): FormGroup {
return this._formBuilder.group( {
title: [data?.title ??'', Validators.required],
description: [data?.description ??'', Validators.required],
id: [data?.id ??Guid.EMPTY]
} );
}
HTML
<!--Mat Sort Test-->
<fieldset>
<div>
<legend>Books</legend>
<table matSort (matSortChange)="sortBook($event)" class="card-table">
<thead class="primary-color">
<tr>
<th mat-sort-header="title">
Book Title
</th>
<th mat-sort-header="description">
Description
</th>
<th class="colums-name">
Actions
</th>
</tr>
</thead>
<tbody>
<tr class="margin-1" formArrayName="bookForm"
*ngFor="let group of bookFormControls; let _i = index;">
<td [formGroupName]="_i">
<input type="text" formControlName="title" class="margin-1 readonly" placeholder="Add title">
</td>
<td [formGroupName]="_i">
<input type="text" formControlName="description" class="margin-1 readonly"
placeholder="Add description">
<input type="hidden" formControlName="id">
</td>
<td style="text-align: center;">
<i (click)="removeBooksAt(_i, 'Title')" class="fa fa-trash margin-right-mini"
style="color:darkgrey; font-size: xx-large;;" aria-hidden="true"></i>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>