Angular: Issue with MatSort causing inconsistency in sorting table columns

As a newcomer to Angular, I find myself working on a project that requires sorting a table based on columns. In my attempt to achieve this, I am utilizing MatSort from Angular Material as shown in this example on Table with Sorting. Despite successfully displaying the table values, I'm encountering difficulties in implementing the sorting functionality.

Below is the code snippet:

admin-user.component.html:

<table mat-table #table [dataSource]="dataSource" matSort class="mat-elevation-z8">

<!-- UserID Column -->
<ng-container matColumnDef="userid">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> User ID </th>
    <td mat-cell *matCellDef="let element"> {{element.userId}} </td>
</ng-container>

<!-- Name Column -->
<ng-container matColumnDef="username">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
    <td mat-cell *matCellDef="let element"> {{element.userName}} </td>
</ng-container>

<!-- Title Column -->
<ng-container matColumnDef="booktitle">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Title </th>
    <td mat-cell *matCellDef="let element"> {{element.bookTitle}} </td>
</ng-container>

<!-- Author Column -->
<ng-container matColumnDef="bookname">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Author </th>
    <td mat-cell *matCellDef="let element"> {{element.bookAuthor}} </td>
</ng-container>

<!-- Issue Date Column -->
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Issue Date </th>
        <td mat-cell *matCellDef="let element"> {{element.issueDate}} </td>
    </ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

admin-user.component.ts:

export class AdminUserComponent implements OnInit {
users: User2[];
displayedColumns: string[] = [
    'userid',
    'username',
    'booktitle',
    'bookname',
    'issuedate'
];
dataSource: MatTableDataSource<IssueDetail>;

@ViewChild(MatSort) sort: MatSort;

issueList: IssueDetail[];

constructor(
    public userService: UserService,
    public bookService: BookService,
    public router: ActivatedRoute
) {
}

ngOnInit() {
    this.issueList = [];
    this.userService.getAllUsers().subscribe(users => {
        this.users = users.filter(user => user.checkout.length > 0);
        for (let i = 0; i < this.users.length; i++) {
            for (let j = 0; j < this.users[i].checkout.length; j++) {
                this.issueList.push(
                    new IssueDetail(
                        this.users[i].id,
                        this.users[i].name,
                        this.users[i].checkout[j].book.title,
                        this.users[i].checkout[j].book.author,
                        this.users[i].checkout[j].startDate + ''
                    )
                );
            }
        }
        this.dataSource = new MatTableDataSource(this.issueList);
        this.dataSource.sort = this.sort;
    });
}}

Thank you for any assistance provided in advance.enter image description here

enter image description here

The IssueDetail class is structured as follows:

export class IssueDetail {
constructor(
    public userId: number,
    public userName: string,
    public bookTitle: string,
    public bookAuthor: string,
    public issueDate: string
) {
}}

It has come to my attention that many examples utilize interfaces for sorting, whereas my implementation focuses on classes. I am unsure if this difference impacts the functionality.

Answer №1

Tip for Angular developers: Utilize the ngAfterViewInit lifecycle hook.

@ViewChild(MatSort) sort: MatSort;

  ngAfterViewInit() {
        this.dataSource.sort = this.sort;
    }

Here's an example of how to use mat-table:

<mat-table [dataSource]="dataSource" matSort>
    <ng-container matColumnDef="date">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Date</mat-header-cell>
        <mat-cell *matCellDef="let element">{{ element.date | date }}</mat-cell>
    </ng-container>
</mat-table>

Answer №2

Consider modifying the following line

...
 this.dataSource = new MatTableDataSource(this.issueList);
...

to this:

this.dataSource.data = this.issueList;

By doing this, you avoid creating a new object and simply update the data. I encountered a similar problem and resolved it using this method. Another potential issue could be the use of *ngIf in a parent container.

Answer №3

Your code looks good, but I suggest trying the following snippet:

setTimeout(() => { 
   this.dataSource.sort = this.sort;
}, 0);

Check out this example

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can a parent component update a child component's prop value in VUE?

I'm facing an issue with managing dynamic props in Vue with TypeScript. Below is my parent component: <script setup lang="ts"> const friends = [ { id: "emanuel", name: "Emanuella e", phone: "08788 ...

Issue: React cannot render Objects as children (received: [object Promise]). If you intended to display multiple children, please use an array instead. (Next)

My dilemma is this: I am trying to display my GitHub repositories on a React component, but I keep encountering the following error: Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, u ...

Guide on resolving the error "Type 'Emits' does not have any call signatures" in Vue 3 with the combination of script setup and TypeScript

I've come across some code that seems to be functioning properly, but my IDE is flagging it with the following warnings: TS2349: This expression is not callable. Type 'Emits' has no call signatures Below is the code snippet in question: ...

Using Angular 8 to implement color changing feature by selecting color on mouseover with color picker

In my journey to develop a custom color picker in Angular 8, I am looking to incorporate a color wheel similar to this. While considering different approaches, one idea I had was to extract useful data from the mouseover event, although I am unsure if this ...

Guide on implementing a cordova plugin in a TypeScript cordova application

In my Cordova project, which utilizes Angular and Typescript, I am facing issues with implementing the juspay-ec-sdk-plugin for Cordova. I have explored possible solutions on StackOverflow related to integrating Cordova plugin in an Angular 4 Typescript ...

The final value of a loop is consistently returned each time

Creating a loop to generate objects. Action.ts public campaing:any = { 'id': '', 'campaing_code': '', 'campaing_type': '', 'start_date': this.currentDate, 'end ...

Is there a way to update the Angular component tag after it has been rendered?

Imagine we have a component in Angular with the selector "grid". @Component({ selector: 'grid', template: '<div>This is a grid.</div>', styleUrls: ['./grid.component.scss'] }) Now, when we include this gri ...

Click on all items to deselect some, but do not select or clear all

I have implemented a kendo grid with multiselect functionality: <kendo-grid [reorderable]="false" class="border" [kendoGridBinding]="data" [selectable]="{ enabled: true, checkboxOnly: false, ...

Issue with Jest mock function failing to trigger axios instance function causing it to return undefined

I initially found a solution on this StackOverflow thread However, I wanted to add my own helper function that generates a fresh Axios instance with the user's authentication token. Here is what I came up with: import axios from "axios"; c ...

Creating a signature for a function that can accept multiple parameter types in TypeScript

I am facing a dilemma with the following code snippet: const func1 = (state: Interface1){ //some code } const func2 = (state: Interface2){ //some other code } const func3: (state: Interface1|Interface2){ //some other code } However, ...

Tips for showcasing the CDK table in Angular without duplicating customer IDs

My CDK table is used to display data, but I am facing an issue with duplicated data in the dataSource as shown below: [ {customerID:"56789", name: "foo", mobile: "123456"}, {customerID:"56789", name: "foo", mobile: "123456"}, {customerID:"12345", name: "f ...

Angular is throwing an error when trying to create a new service: "Workspace must be loaded before it can be used."

Having trouble adding pusher.js to my angular.json file. After trying to create a new service, I encountered the following error: Error: Workspace needs to be loaded before it is used. Any tips on how to resolve this? I attempted to update the angular cl ...

Date selection feature in Material UI causing application malfunction when using defaultValue attribute with Typescript

Recently, I discovered the amazing functionality of the Material UI library and decided to try out their date pickers. Everything seemed fine at first, but now I'm facing an issue that has left me puzzled. Below is a snippet of my code (which closely ...

What is the process for connecting a global variable to a BehaviorSubject?

I'm currently working on implementing a login feature in my application, and I want specific buttons within the app.component template to only be visible once the user successfully logs in. To achieve this, I am attempting to utilize BehaviorSubject. ...

Best method for locating type declarations in TypeScript 2.0

Ever since typescript 2.0 rolled out, the use of typings has been replaced with npm install @types/<package-name>. In the old typings system, we had the typings search command for package searches. But now I wonder - what is the standard way to sear ...

When transferring type validation code to a separate function, Typescript throws an error stating "property does not exist on type"

While working on tests, I encountered a situation where my type validation code behaves differently based on its placement within the codebase. Specifically, when I have my error-throwing type validation code within the same function, Typescript is able to ...

Utilizing an array for substituting sections of a string: a guide

I have an array of values like ['123', '456', '789']. What is the best way to iterate over this array and update parts of a string that contain the text :id in sequence (e.g. users/:id/games/:id/server/:id)? Currently, I&apos ...

How can I add an apostrophe (') into the regex expression within an Angular application?

This regular expression is designed to validate an address input field that can include special characters such as period (.), apostrophe ('), hyphen (-), number, pound sign (#), at symbol (@), ampersand (&), forward slash (/), and spaces. Howeve ...

Exploring the Children Property in TypeScript and the Latest Version of React

Within my App.tsx file, I am passing <Left /> and <Right /> as components to an imported component named <SplitScreen />. It seems that in React 18, the "children" prop needs to be explicitly typed. When I type it as React.Element[], eve ...

What is the method to send numerous forms with a single click on Angular Material Stepper?

My user interface presents a unique scenario that is different from the question posed. To address the issue of submitting forms within a stepper in Angular 4 Material, I have set up a situation where I need to create a single stepper containing multiple f ...