Components: [Table] Collation for languages where alphabetical order is different from Unicode order

Created on 30 Aug 2019  路  5Comments  路  Source: angular/components

Feature Description

In Norwegian and Danish Alphabets, the correct order of the Norwegian/Danish characters are:

However, the Unicode order for these characters are:

  1. 脜 (197)
  2. 脝 (198)
  3. 脴 (216)

Could collation be implemented to solve this?

Use Case

Here is a stackblitz with a table that can be sorted by "No." and "Name":

https://stackblitz.com/edit/angular-an1uqc-8mdqns

If you sort by "Name" the name starting with "脜" comes before "脝" and "脴".
If the sorting was following the alphabetical order of Norwegian/Danish, the name starting with "脝" would come before "脴" and "脜".

As it stands now, the sorting of names with Norwegian and Danish characters are incorrect.

Thanks for reading! 馃槃

P4 materiatable feature has pr needs discussion

Most helpful comment

This can be achieved by using a custom sort implementation via a matSortChange event handler and String.prototype.localeCompare with an a locale, in this case da-DK, passed in.

<table mat-table [dataSource]="sortedData" matSort (matSortChange)="sortData($event)">
@Component({
  selector: 'table-sorting-example',
  styleUrls: ['table-sorting-example.css'],
  templateUrl: 'table-sorting-example.html',
})
export class TableSortingExample {
  displayedColumns: string[] = ['position', 'name', 'description'];
  sortedData: TestElement[] = [];

  constructor() {
    this.sortedData = ELEMENT_DATA.slice();
  }

  sortData(sort: Sort) {
    console.log(JSON.stringify(sort));

    const data = ELEMENT_DATA.slice();
    if (!sort.active || sort.direction === '') {
      this.sortedData = data;
      return;
    }

    const isAsc = sort.direction === 'asc';

    this.sortedData = data.sort((a, b) => {
      switch (sort.active) {
        case 'position': return compareNumber(a.position, b.position, isAsc);
        case 'name': return compareString(a.name, b.name, isAsc);
        case 'description': return compareString(a.description, b.description, isAsc);
        default: return 0;
      }
    });
  }
}
function compareString(a: string, b: string, isAsc: boolean) {
  return a.localeCompare(b, 'da-DK') * (isAsc ? 1 : -1);
}

Here is an example in action:
https://stackblitz.com/edit/angular-an1uqc-jv1s6z

All 5 comments

The MatTableDataSource is meant to be a super simple "getting started" data source more than anything else. The intent is that, for more complex scenarios (e.g. robust i18n, server-side operations, etc.), apps would create their own data source.

Our docs could probably do a better job of communicating this, though.

@jelbourn the data in the table in my stackblitz example is this:

```const ELEMENT_DATA: TestElement[] = [
{position: 1, name: 'Alpha', description: 'Test123'},
{position: 2, name: 'Bravo', description: '0'},
{position: 3, name: 'Charlie', description: 'aaa'},
{position: 4, name: 'Delta', description: ''},
{position: 5, name: 'Echo', description: '1'},
{position: 6, name: 'Foxtrot', description: '2'},
{position: 7, name: '脝Gamma', description: ''},
{position: 8, name: '脴Hotel', description: '3'},
{position: 9, name: '脜Indigo', description: '1000'},

];
```
The correct way to sort the last three items (脝Gamma, 脴Hotel and 脜Indigo) according to the Norwegian/Danish alphabet would be:

  1. 脝Gamma
  2. 脴Hotel
  3. 脜Indigo

But MatSort uses the Unicode numbers for these characters and sorts like this instead:

  1. 脜Indigo (197)
  2. 脝Gamma (198)
  3. 脴Hotel (216)

How can a different data source cause MatSort to sort on something else than the Unicode numbers for these characters without using something like collation?

Sorry if i misunderstood your previous answer.

It would be however these strings are normally sorted in locales where the characters are used; I don't actually know how people do this myself.

This can be achieved by using a custom sort implementation via a matSortChange event handler and String.prototype.localeCompare with an a locale, in this case da-DK, passed in.

<table mat-table [dataSource]="sortedData" matSort (matSortChange)="sortData($event)">
@Component({
  selector: 'table-sorting-example',
  styleUrls: ['table-sorting-example.css'],
  templateUrl: 'table-sorting-example.html',
})
export class TableSortingExample {
  displayedColumns: string[] = ['position', 'name', 'description'];
  sortedData: TestElement[] = [];

  constructor() {
    this.sortedData = ELEMENT_DATA.slice();
  }

  sortData(sort: Sort) {
    console.log(JSON.stringify(sort));

    const data = ELEMENT_DATA.slice();
    if (!sort.active || sort.direction === '') {
      this.sortedData = data;
      return;
    }

    const isAsc = sort.direction === 'asc';

    this.sortedData = data.sort((a, b) => {
      switch (sort.active) {
        case 'position': return compareNumber(a.position, b.position, isAsc);
        case 'name': return compareString(a.name, b.name, isAsc);
        case 'description': return compareString(a.description, b.description, isAsc);
        default: return 0;
      }
    });
  }
}
function compareString(a: string, b: string, isAsc: boolean) {
  return a.localeCompare(b, 'da-DK') * (isAsc ? 1 : -1);
}

Here is an example in action:
https://stackblitz.com/edit/angular-an1uqc-jv1s6z

Thank you so much @alexstaroselsky this was really helpful! 馃槃
@jelbourn perhaps this could be added as an example? 馃樁
https://material.angular.io/components/sort/overview

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MurhafSousli picture MurhafSousli  路  3Comments

vanor89 picture vanor89  路  3Comments

Miiekeee picture Miiekeee  路  3Comments

kara picture kara  路  3Comments

julianobrasil picture julianobrasil  路  3Comments