Elo
Elo

Reputation: 41

Why agular material sort displays arrows but doesn't sort the column?

I would like make my table sortable. For that I use https://material.angular.io/components/sort/overview. The "Sort Header" works in the other tables of the web-app, I read the doc, watched tutorials .. I don't understand why in this specific component it doesn't work...

  1. The matSort and mat-sort-header seems to be well positioned because I see the arrows in my table, they are clickable but nothing is happening

  2. import { MatSortModule } from '@angular/material/sort' is well imported in admin.module.ts

  3. Component, OnInit, ViewChild, MatSort are well imported in user.component.ts

  4. @ViewChild(MatSort, { static: true }) sort: MatSort; in the export class UserComponent implements OnInit

  5. this.dataSource.sort = this.sort; in ngOnInit

Somebody to help me ?

THE CODE

user.component.ts :

import { Component, OnInit, ViewChild } from '@angular/core';
//[...]other imports
import { MatSort } from '@angular/material/sort';


@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.less'],
})
export class UserComponent implements OnInit {
  public translatePage: ComponentsTrslt = ComponentsTrslt.PROFILE;
  users: UserItem[] = []; // contains users get from back
  public dataSource: MatTableDataSource<UserItem>; // users that will be displayed in a material way
  public displayedColumns: string[] = [
    'email',
    'firstName',
    'lastName',
    'userRating',
    'coreHour',
    'action',
  ]; // columns to display
  public pageSize = 10; // default displayed elements number
  public currentPage = 0; // default displayed page
  public totalSize = 0; // default number of element in dataSource (not set yet)
  @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator; // paginator at the bottom of the page

  // sorted data
  @ViewChild(MatSort, { static: true }) sort: MatSort;

  // [...]  other code... : Popups / Dialog boxes   +  Edition data passed to forms / fields  ... 


  constructor(
    public translateService: TranslationService,
    private userService: UserService,
    private expertService: ExpertService,
    private clientService: ClientService,
    private router: Router,
    private snackBar: MatSnackBar,
    private formBuilder: FormBuilder,
    public dialog: MatDialog,
    public languageService: LanguageService
  ) {
   
  }

  ngOnInit(): void {
    this.fetchAndMapUsers(); // include this.dataSource.sort = this.sort;
    this.editExpertProfileForm = this.formBuilder.group({
      lastName: '',
      firstName: '',
      email: '',
      phone: '',
      company: '',
      title: '',
      wage: '',
      citizenship: '',
      country: '',
      city: '',
      address: '',
      zipCode: '',
      rating: [{ value: null }],
    });
    this.editProfileForm = this.formBuilder.group({
      lastName: '',
      firstName: '',
      email: '',
      phone: '',
      company: '',
      service: '',
      citizenship: '',
      country: '',
      city: '',
      address: '',
      zipCode: '',
      languages: [],
    });
    this.editRatingForm = this.formBuilder.group({
      id: '',
      userId: '',
      title: '',
      rating: '',
      wage: '',
      available: '',
    });
    this.editCoreHourForm = this.formBuilder.group({
      coreHour: 0,
    });
  }

 
  
// Get expert data from User Id
    this.expertService.getByUserId(expertId).subscribe((data) => {
      // Send data to form
      this.editRatingForm.setValue({
        id: data.id,
        userId: data.userId,
        title: '',
        rating: data.rating,
        wage: '',
        available: '',
      });

      this.expertInfoEdition = data;
      this.expertRatingEdition = data.rating;
      this.editModeRating = !this.editModeRating;
    });
  }


  // Get all users from back
  private fetchAndMapUsers(): void {
    this.userService.getAll().subscribe((data) => {
      console.log(data);
      this.mapUsers(data); // include this.dataSource.sort = this.sort;
    });
  }

  // populateTable() {
  //   this.userService.getAll()
  //       .subscribe(data => {
  //               this.results = data;
  //               this.dataSource = new MatTableDataSource(this.results);
  //               this.dataSource.sort = this.sort;
  //           })}

  public handlePage(e: any) {
    this.currentPage = e.pageIndex;
    this.pageSize = e.pageSize;
    this.iterator();
  }

  private iterator() {
    const end = (this.currentPage + 1) * this.pageSize;
    const start = this.currentPage * this.pageSize;
    const part = this.users.slice(start, end);
    this.dataSource = new MatTableDataSource<UserItem>(part);
  }

  // Create the list of users from the users got by the call to back
  private mapUsers(data): void {
    // Fill the list of users from the users got by the call to back
    this.users = data.map((element) => {
      const ui: UserItem = {
        userId: element.id,
        email: element.email,
        firstName: element.firstName,
        lastName: element.lastName,
        isValidated: element.isValidated,
        isAdmin: element.isAdmin,
        isPremiumCommunity: element.isPremiumCommunity,
        hasCommunityAccess: element.hasCommunityAccess,
        userRating: null,
        coreHour: null,
      };
      this.userService.get(element.id).subscribe((userData) => {
        ui.coreHour = userData.creditsTimeRatio;
        if (userData.expertId) {
          this.expertService.get(userData.expertId).subscribe((expertData) => {
            ui.userRating = expertData.rating;
          });
        }
      });
      if (!element.isDisabled) {
        return ui;
      }
    });

    // Sort by email address before displaying the list
    this.users.sort((user1, user2) => {
      if (user1.email < user2.email) {
        return -1;
      }
      if (user1.email > user2.email) {
        return 1;
      }
      return 0;
    });
    // setting datasource of table from users
    this.dataSource = new MatTableDataSource<UserItem>(this.users);
    this.dataSource.sort = this.sort;
    console.log(' this.dataSource',  this.dataSource); // return is ok and complete cf screenshot
    this.dataSource.sortingDataAccessor = (
      element: any,
      sortHeaderId: string
    ): string => {
      if (typeof element[sortHeaderId] === 'string') {
        return element[sortHeaderId].toLocaleLowerCase();
      }
      return element[sortHeaderId];
    };
    this.dataSource.paginator = this.paginator;
    this.totalSize = this.users.length;
    this.iterator();
  }

  // [...] + several functions : especially to update data

user.component.html :

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

    <!-- E-Mail Column -->
    <ng-container matColumnDef="email">
      <mat-header-cell *matHeaderCellDef mat-sort-header>
        E-Mail
      </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{ element.email }} </mat-cell>
    </ng-container>
  
    <!-- First Name Column -->
    <ng-container matColumnDef="firstName">
      <mat-header-cell *matHeaderCellDef mat-sort-header>
        First Name
      </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{ element.firstName }} </mat-cell>
    </ng-container>
  
    <!-- Last Name Column -->
    <ng-container matColumnDef="lastName">
      <mat-header-cell *matHeaderCellDef mat-sort-header>
        Last Name
      </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{ element.lastName }} </mat-cell>
    </ng-container>
  
    <!-- Rating Column -->
    <ng-container matColumnDef="userRating">
      <mat-header-cell *matHeaderCellDef mat-sort-header>
        Rating
      </mat-header-cell>
  
      <mat-cell *matCellDef="let element" class="ratingCell">
        {{ element.userRating }}
        <button
          class="editRatingButton"
          mat-button
          color="stroked"
          *ngIf="element.userRating"
          matTooltip="Edit user rating"
          (click)="OpClExRatingEdit(element.userId)"
        >
          Edit
        </button>
      </mat-cell>
    </ng-container>
  
     <!-- [...] etc... more or less the same template for all the others columns -->
    
  </mat-table>

  <mat-paginator
    #paginator
    [pageSize]="pageSize"
    [pageSizeOptions]="[5, 10, 100]"
    [showFirstLastButtons]="true"
    [length]="totalSize"
    [pageIndex]="currentPage"
    (page)="handlePage($event)"
  ></mat-paginator>
  
  <!--some edit pop up-->
  <div class="editPopup" *ngIf="editModeExpert">
    <mat-card>
        <form>
            <!-- [...] -->
      </form>
    </mat-card>
  </div>
  

  <div class="editPopup" *ngIf="editModeClient">
    <mat-card>
      <form>
         <!-- [...] -->
      </form>
    </mat-card>
  </div>
  
  
  <div class="editRatingPopup" *ngIf="editModeRating">
    <mat-card>
        <form>
            <!-- [...] -->
         </form>
    </mat-card>
  </div>

user-item.ts :

export interface UserItem {
  email: string;
  firstName: string;
  lastName: string;
  userId: string;
  isValidated: boolean;
  isAdmin: boolean;
  hasCommunityAccess: boolean;
  isPremiumCommunity: boolean;
  userRating: number;
  coreHour: number;
}

console log screenshot: enter image description here thank you !

Upvotes: 1

Views: 709

Answers (1)

Elo
Elo

Reputation: 41

[resolved]

1/Sorting didn't work because (I didn't see...) 'this.dataSource' was also set in an other function: see below

 private iterator() {
    const end = (this.currentPage + 1) * this.pageSize;
    const start = this.currentPage * this.pageSize;
    const part = this.users.slice(start, end);
    // this.dataSource = new MatTableDataSource<UserItem>(part); // init dataSource here create a bugg for the table's sorting
  }

2/ Other pb I met. In another table. When I clicked on the sort arrow, that created new tables in my cell... very weird, the cells in my table were completely disorganized. Well, the solution:

In x.component.ts, change the 'trigger':

Insteed of:

trigger('detailExpand', [
  state('collapsed', style({ height: '0px', minHeight: '0', display: 'none' })),
  state('expanded', style({ height: '*' })),
  transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
])

try:

trigger('detailExpand', [
  state('collapsed, void', style({ height: '0px', minHeight: '0', display: 'none' })),
  state('expanded', style({ height: '*' })),
  transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
  transition('expanded <=> void', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
])

(solution found on github.com)

Hope it will help somebody... !

Upvotes: 2

Related Questions