0
votes

I have a requirement where in a HTML table I have to sort the table's values based on a property name. Please refer the code below

<h2>{{modifiedBy}} {{order}}</h2>
<table class="table table-striped border mt-1">
    <thead>
        <tr>
            <th scope="col" (click)="sortBy('id', 'desc')">Id <i *ngIf="modifiedBy!=='id'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && modifiedBy==='id'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='id'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('name', 'desc')">Name
                <i *ngIf="modifiedBy!=='name'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && modifiedBy==='name'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='name'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('age', 'desc')">Age
                <i *ngIf="modifiedBy!=='age'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && modifiedBy==='age'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='age'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('dob', 'desc')">Date Of Birth
                <i *ngIf="order==='asc' && modifiedBy==='dob'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && modifiedBy==='dob'" class="fa fa-arrow-up"></i>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let data of dataList | orderBy:modifiedBy:order:dateType">
            <td>{{ data.id }}</td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.dob }}</td>
        </tr>
    </tbody>
</table>

On load, the table will be sorted in descending order with the "dob" property and an arrow icon for the "dob" table header cell will have an arrow pointing up and for the rest it will be pointing down (asc:arrow down, desc:arrow up).

Now what I want to do whenever I click any table header cell which is to be sorted is to sort the table data based on the clicked table header cell's property and the arrow icon should change based on the sort order that is asc or desc. Please note that while sorting a table head, it should not disturb the arrow icons of the other table header cells.

I have put up some code which is partially working. I can't proceed further as I'm struggling with rest of the logic. Additionally, I'm using two icons conditionally for each table head. Will it possible to use a single icon for each table head?

StackBlitz

2

2 Answers

0
votes

Since you are on Angular, there are a few libraries available that implement sorting table. This helps when you need to deliver something fast and you don't have time to lose on trivial things. But this depends on your requirement as well. For example, you can install the ngx-datatable package in your angular application https://swimlane.github.io/ngx-datatable/ .These are highly configurable and come with some nice designs as well.

I tried to see whats the issue in your example. The code is a bit messy, I tried to cater to all conditions since there is no condition for dob when you click on another header. You can play with the conditions to get the right behavior:

  1. The First step, you can implement OnIgnit as below.

    import { Component, OnInit, VERSION } from "@angular/core";
    
    export class AppComponent implements OnInit {
    name = "Angular " + VERSION.major;
    modifiedBy = "";
    order = "";
    dateType = "";
    
    ngOnInit(): void {
     this.order = "desc";
     this.modifiedBy = "dob";
     this.dateType = "date";
    }
    
  2. Reassign the orderBy to order.

    sortBy(propertyName, orderBy) {
    this.order = orderBy;
    if (propertyName === "dob") {
    this.dateType = "date";
    } else {
     this.dateType = "";
    }
    this.modifiedBy = propertyName;
    if (this.order === "asc") {
     this.order = "desc";
     } else if (this.order === "desc") {
     this.order = "asc";
    }
    

    } }

  3. In your HTML, the icon is disappearing when clicking on the other header, I think you will need to have all the possible options when clicking on the other header as well.

     <th scope="col" (click)="sortBy('dob', 'desc')">Date Of Birth
             <i *ngIf="order==='desc' && modifiedBy==='dob'" class="fa fa-arrow-up"></i>
             <i *ngIf="order==='asc' && modifiedBy==='dob'" class="fa fa-arrow-down"></i>
             <i *ngIf="order==='asc' && modifiedBy==='name'" class="fa fa-arrow-up"></i>
             <i *ngIf="order==='desc' && modifiedBy==='name'" class="fa fa-arrow-up"></i>
             <i *ngIf="order==='asc' && modifiedBy==='age'" class="fa fa-arrow-up"></i>
             <i *ngIf="order==='desc' && modifiedBy==='age'" class="fa fa-arrow-up"></i>
             <i *ngIf="order==='asc' && modifiedBy==='id'" class="fa fa-arrow-up"></i>
             <i *ngIf="order==='desc' && modifiedBy==='id'" class="fa fa-arrow-up"></i>
         </th>
    
0
votes

personally I'd have Age and DOB arrows pointing the same direction as, in theory, they should be in the same order (unless age is based on a different date for different records).

<h2>{{modifiedBy}} {{order}}</h2>
<table class="table table-striped border mt-1">
    <thead>
        <tr>
            <th scope="col" (click)="sortBy('id', 'desc')">Id 
                <i *ngIf="order==='desc' || modifiedBy!=='id'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='id'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('name', 'desc')">Name
                <i *ngIf="order==='desc' || modifiedBy!=='name'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='name'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('age', 'desc')">Age
                <i *ngIf="order==='asc' || (modifiedBy!=='dob' && modifiedBy!=='age')" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && (modifiedBy==='dob' || modifiedBy==='age')" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('dob', 'desc')">Date Of Birth
                <i *ngIf="order==='asc' || (modifiedBy!=='dob' && modifiedBy!=='age')" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && (modifiedBy==='dob' || modifiedBy==='age')" class="fa fa-arrow-up"></i>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let data of dataList | orderBy:modifiedBy:order:dateType">
            <td>{{ data.id }}</td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.dob }}</td>
        </tr>
    </tbody>
</table>

However if you wish to keep them independant:

<h2>{{modifiedBy}} {{order}}</h2>
<table class="table table-striped border mt-1">
    <thead>
        <tr>
            <th scope="col" (click)="sortBy('id', 'desc')">Id 
                <i *ngIf="order==='desc' || modifiedBy!=='id'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='id'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('name', 'desc')">Name
                <i *ngIf="order==='desc' || modifiedBy!=='name'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='name'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('age', 'desc')">Age
                <i *ngIf="order==='desc' || modifiedBy!=='age'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='asc' && modifiedBy==='age'" class="fa fa-arrow-up"></i>
            </th>
            <th scope="col" (click)="sortBy('dob', 'desc')">Date Of Birth
                <i *ngIf="order==='asc' || modifiedBy!=='dob'" class="fa fa-arrow-down"></i>
                <i *ngIf="order==='desc' && modifiedBy==='dob'" class="fa fa-arrow-up"></i>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let data of dataList | orderBy:modifiedBy:order:dateType">
            <td>{{ data.id }}</td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.dob }}</td>
        </tr>
    </tbody>
</table>