IgxGrid は ISortingStrategy を実装することでソート方法をカスタマイズすることができます。
この方法を応用して、欠損値として “-” や “*” や “” (空文字列) などが使われている場合に、欠損値を null や undefined と同じとみなしてソートする方法をご紹介します。
この記事で扱うデータ
下のコードはこの記事で使用するデータです。Col1 フィールドは数値型もしくは文字列型と定義されていて、欠損値として “-” が使用されています。
// src\app\sampleData.ts
export interface SampleDataType {
ID: number;
Col1: number | string;
}
export const SampleData: SampleDataType[] = [
{ ID: 1, Col1: 1 },
{ ID: 2, Col1: 8 },
{ ID: 3, Col1: 5 },
{ ID: 4, Col1: '-' }, // 欠損値
{ ID: 5, Col1: 3 },
{ ID: 6, Col1: '-' }, // 欠損値
{ ID: 7, Col1: 6 },
{ ID: 7, Col1: 12 },
]
このデータを IgxGrid にバインドして Col1 で並べ替えた場合に、昇順のときは ‘-‘ が一番最初に、降順のときは一番最後にさせてみましょう。
第一段階 : データを igx-grid に表示するまで
App コンポーネント側
// src\app\app.component.ts
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { IgxGridModule, ISortingStrategy} from '@infragistics/igniteui-angular';
import { SampleDataType, SampleData } from './sampleData'; // 「この記事で扱うデータ」で提示しているデータを読み込みます
@Component({
selector: 'app-root',
imports: [RouterOutlet, IgxGridModule],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent implements OnInit {
title = 'kb15005-app1';
public data: SampleDataType[] = SampleData; // 読み込んだデータを data に設定します。
constructor() {}
ngOnInit() {
}
}
- 7 行目 : この一つ前のセクション「この記事で扱うデータ」で提示したデータを読み込みます。
- 17 行目 : 読み込んだデータを data に設定します。
App コンポーネント テンプレート側
<!-- src\app\app.component.html -->
<div class="my_wrapper">
<igx-grid #grid1 [data]="data" [autoGenerate]="false" [primaryKey]="'ID'" height="600px">
<igx-column field="ID" header="ID" [dataType]="'number'" [sortable]="true"></igx-column>
<igx-column field="Col1" header="Col1" [dataType]="'string'" [sortable]="true">
</igx-column>
</igx-grid>
</div>
- 4 行目 : igx-grid の data に読み込んだデータを設定します。
- 6 行目 : Col1 の dataType を string にしていることに注目です。SampleDataType の Col1 フィールドの定義を思い出してください。数値もしくは文字列でした。ここで dataType を number としてしまうと、数値に変換できない文字列が来たときにエラーが発生して表示できません。string であればどのようなものが来ても igx-grid は string に変換して表示させようとしますので、そのようなエラーを回避することができます。
- 5、6 行目の各 igx-column : sortable を trueにして並べ替え機能を有効にします。
実行結果
igx-grid にデータを表示させ、ソート機能を有効にするところまでできました。

第二段階 : ISortingStrategy を実装したクラスを実装する
今回は CustomSortingStrategy という名前のクラスを作成し、そこに ISortingStrategy を実装していきましょう。
まず src フォルダーの下に lib フォルダーを作成し、その下に CustomSortingStrategy.ts ファイルを作成します。

ISortingStrategy を実装したクラスをゼロから作成するのは大変ですので、igniteui-angular に組み込まれているデフォルトの ISortingStrategy の実装クラスをコピーしてきて必要な箇所だけ変更していくことにします。デフォルトの ISortingStrategy の実装クラスは GitHub にあり、こちらの DefaultSortingStrategy クラスがそれです。
コピーしてきたら、compareValue の null 値かもしくは undefined 値かを判定している部分に、’-‘ かどうかも追加します。
// src\lib\CustomSortingStrategy.ts
public compareValues(a: any, b: any): number {
const an = (a === null || a === undefined || a === '-'); // '-'もnullやundefined判定のところに加える
const bn = (b === null || b === undefined || b === '-'); // '-'もnullやundefined判定のところに加える
if (an) {
if (bn) {
return 0;
}
return -1;
} else if (bn) {
return 1;
}
return a > b ? 1 : a < b ? -1 : 0;
}
また、本題とは離れますが、このままでは一部のコードでエラーが発生してしまうので、そこも修正しておきます。
// src\lib\CustomSortingStrategy.ts
... (中略) ...
// コンストラクターをpublicに変更します。
public constructor() { }
... (中略) ...
public sort( ... 中略 ... )
) {
const key = fieldName;
const reverse = (dir === SortingDirection.Desc ? -1 : 1);
// isDateおよびisTimeがnullのときはfalseを設定するように変更します。
const cmpFunc = (obj1: any, obj2: any) => this.compareObjects(obj1, obj2, key, reverse, ignoreCase, valueResolver, isDate ?? false, isTime ?? false);
return this.arraySort(data, cmpFunc);
}
これで ISortingStrategy を実装した CustomSortingStrategy クラスの実装は完成です。最終的にはこのようなコードになります。
// src\lib\CustomSortingStrategy.ts
import { ISortingStrategy, SortingDirection } from '@infragistics/igniteui-angular';
export class CustomSortingStrategy implements ISortingStrategy {
protected static _instance: CustomSortingStrategy | null = null;
// コンストラクターをpublicに変更します。
public constructor() { }
public static instance(): CustomSortingStrategy {
return this._instance || (this._instance = new this());
}
public sort(
data: any[],
fieldName: string,
dir: SortingDirection,
ignoreCase: boolean,
valueResolver: (obj: any, key: string, isDate?: boolean) => any,
isDate?: boolean,
isTime?: boolean
) {
const key = fieldName;
const reverse = (dir === SortingDirection.Desc ? -1 : 1);
// isDateおよびisTimeがnullのときはfalseを設定するように変更します。
const cmpFunc = (obj1: any, obj2: any) => this.compareObjects(obj1, obj2, key, reverse, ignoreCase, valueResolver, isDate ?? false, isTime ?? false);
return this.arraySort(data, cmpFunc);
}
public compareValues(a: any, b: any): number {
const an = (a === null || a === undefined || a === '-'); // '-'をnullやundefinedと同じとして扱う処理を追加します
const bn = (b === null || b === undefined || b === '-'); // '-'をnullやundefinedと同じとして扱う処理を追加します
if (an) {
if (bn) {
return 0;
}
return -1;
} else if (bn) {
return 1;
}
return a > b ? 1 : a < b ? -1 : 0;
}
protected compareObjects(
obj1: any,
obj2: any,
key: string,
reverse: number,
ignoreCase: boolean,
valueResolver: (obj: any, key: string, isDate?: boolean, isTime?: boolean) => any,
isDate: boolean,
isTime: boolean
) {
let a = valueResolver.call(this, obj1, key, isDate, isTime);
let b = valueResolver.call(this, obj2, key, isDate, isTime);
if (ignoreCase) {
a = a && a.toLowerCase ? a.toLowerCase() : a;
b = b && b.toLowerCase ? b.toLowerCase() : b;
}
return reverse * this.compareValues(a, b);
}
protected arraySort(data: any[], compareFn?: (arg0: any, arg1: any) => number): any[] {
return data.sort(compareFn);
}
}
第三段階 : CustomSortingStrategy を Col1 列に適用する
ここまでくればあともう一息です!
App コンポーネント側
作成した CustomSortingStrategy をインポートし、オブジェクトを作成します。
// src\app\app.component.ts
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { IgxGridModule, ISortingStrategy} from '@infragistics/igniteui-angular';
import { SampleDataType, SampleData } from './sampleData';
import { CustomSortingStrategy } from '../lib/CustomSortingStrategy'; // ここ!CustomSortingStrategyをインポートします。
@Component({
selector: 'app-root',
imports: [RouterOutlet, IgxGridModule],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent implements OnInit {
title = 'kb15005-app1';
public data: SampleDataType[] = SampleData;
public col1CustomSortingStrategy: ISortingStrategy = new CustomSortingStrategy(); // ここ!CustomSortingStrategyオブジェクトを作成し、col1CustomSortingStrategyに代入します。
constructor() {}
ngOnInit() {
}
}
App コンポーネント テンプレート側
Col1 の igx-column の sortStrategy で CustomSortingStrategy オブジェクトを指定します。
<!-- src\app\app.component.html -->
<div class="my_wrapper">
<igx-grid #grid1 [data]="data" [autoGenerate]="false" [primaryKey]="'ID'" height="600px">
<igx-column field="ID" header="ID" [dataType]="'number'" [sortable]="true"></igx-column>
<!--
sortStrategyでCol1のカスタムソートを設定します。
-->
<igx-column
field="Col1" header="Col1" [dataType]="'string'" [sortable]="true"
[sortStrategy]="col1CustomSortingStrategy">
</igx-column>
</igx-grid>
</div>
以上ですべて完了です!
実行結果
Col1 列を昇順で並べ替えた場合

“-” が先頭に来るようになりました! しかも 12 も数値として並べ替えられていて、ちゃんと最後に来るようになっています。
Col1 列を降順で並べ替えた場合

こちらも同様ですね! “-” が最後に来て、12 も数値として並べ替えられています。