Jobelle
Jobelle

Reputation: 2834

Angular mat-table : - Sort icon missing on custom sort

The mat-sort icon is not showing when we sort the mat table by code. How can do the sort on clicking the button rather than clicking on the mat- header.

StackBlitzzzz Link

Upvotes: 4

Views: 7346

Answers (1)

Robert
Robert

Reputation: 564

Initially I thought that the problem was simple but going ahead and reading the documentation and the source code, Angular material does not offer this functionality, it can be seen that is not working by subscribing to:

 ngAfterViewInit() {
    this.sort.sortChange.subscribe((x) => {
      console.log(x);
    });
  }

The console response will be:

{active: "name", direction: "asc"}

So the id of the column will be triggered and the sort will be implemented on it, but the icon will not appaer.

I came with 2 implementations, your choice to choose witch one fit for you.

SOLUTION 1:

A quick fix but a little hugly will be to force the display of all the icon but will not have so much sense because we want to focus on a single column. To do that just past this in css:

::ng-deep .mat-sort-header-arrow {
  opacity: 1 !important;
 }

All the icons on header will be displayed only on header that have mat-sort-header attribute, and the icon change wil be triggered on the active column.

Stackblitz: https://stackblitz.com/edit/mattable-with-custom-sort-etzkcy

SOLUTION 2:

This is a bit hacky, so in order to trigger the animation on the icon we need to click on the header. So to that, i call a click event from component on mat-header-cell, but mat-header-cell is not clickable so i wrap the column name inside a div, in order to simulate the click

      <mat-header-cell *matHeaderCellDef mat-sort-header>
        <div #position>Position</div>
      </mat-header-cell> 

In the component we need to create a viewchildren for all the displayedColumns that we want to simulate the click:

@ViewChild('position') position:ElementRef;
@ViewChild('name') name:ElementRef; 

In your method sortTest(val) i start to be a lot more hacky, so i switch the value of the string passed as parameter in val, to call the right click on the right header, bacause the name of the div and of the column are 1:1

 switch(val) {
      case "name": { 
        this.name.nativeElement.click()
        this.name.nativeElement.click()            
        break; 
        } 
      case "position": { 
        this.position.nativeElement.click()
        this.position.nativeElement.click()            
        break; 
      }
    } 

Why i call

            this.position.nativeElement.click()

2 times? Bacause from what i understand

    this.sort.active = val;

is counted as a click but without displaying the icon, so we will asc desc returning at the previously order, in order to avoid that i call it 2 time se the clicks are odd.

After all this hacky code i emit the sort

this.sort.active = val;

    this.dataSource.sort = this.sort;
    const sortState: Sort = {active: val, direction: this.sort.direction === 'asc' ? 'desc' : 'asc'};

    this.sort.direction = sortState.direction;
    this.sort.sortChange.emit(sortState); 

I didn't figure out a better solution, even searching online, on the documentation, and on the sourcecode of angular material. I found a question like that without a single response.

Stackblitz of this solution: https://stackblitz.com/edit/mattable-with-custom-sort-emqkbs

Upvotes: 6

Related Questions