igx-grid のセル、行、列ヘッダーのスタイリング方法さまざま

*2018/12/11(Tue) 時点の情報に基づいています*

前々回は `igx-grid` の基本的な構成、前回は機能の有効化について紹介してきました。

ある程度動くのを見ると、次にやりたくなるのがスタイリングかと思います。

もちろん `igx-grid` にはスタイリングのための仕組みがあるので、色々と紹介していきたいと思います。

## セルとセルの間に縦線を引きたい
一番よくあるのが、セルとセルの間に縦線を引きたい、というスタイリングではないでしょうか。

`igx-column` には **[cellClasses](https://jp.infragistics.com/products/ignite-ui-angular/docs/typescript/classes/igxcolumncomponent.html#cellclasses)** というプロパティがあり、セルに任意のCSSクラスを追加することができます。

全セルにボーダースタイルを適用することで、縦線を表現することができます。具体的には以下のようになります。

```html:app.component.html
    <igx-column *ngFor="let column of columns"
                [field]="column.field"
                [header]="column.header"
                [dataType]="column.dataType"
                [width]="column.width"
                [cellClasses]="{ 'bordered-cell': true }"
                ...>
    </igx-column>
```
`bordered-cell` というCSSクラスをセルに追加している例です。CSSクラスを付与するだけにしては少し大げさに感じるかもしれません。`cellClasses` はオブジェクトを受け入れ、TypeScript の型で表すと 

```typescript
{ [key: string]: boolean | Function }
```
- key: string 型で、付与するCSSクラス名を指定します。
- value: 以下の2種類の型を受け入れます。
    - boolean: true -> 同じ列の全セルに付与される / false -> 同じ列の全セルに付与されない
    - Function: true/false を返す関数で、true に合致した特定のセルにのみCSSクラスが付与される

となっていて、**条件付きセルスタイリング**を実現するためにこのような仕組みになっています。

ここでは単に `true` をセットして全セルに `bordered-cell` が付与されるようにしています。

あとは実際に `bordered-cell` クラスを定義していきますが、Angular Component はデフォルトでは ViewEncapsulation が有効なので **`::ng-deep`でネストしなくてはいけない** 点に注意が必要です。

```scss:app.component.scss
:host::ng-deep {
  .bordered-cell {
    border-right: 1px solid rgba(0, 0, 0, .08); 
  }
}
```
正しく設定できると以下のように変わります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/70618/a46f6468-7245-e005-8f1a-f25379bf1233.png)

## セルの値が true の場合だけ背景色を変更したい
というように、特定の条件を満たす場合にのみスタイリングを適用したい、というニーズも多くあります。

その場合は、先ほどの `cellClasses` で、value に Function を指定することで条件付きセルスタイリングを実現することができます。

ロジックを書くことになるので、htmlテンプレートではなく、TypeScript側に実装します。

```typescript:app.component.ts
export class AppComponent implements OnInit {
  ...
  cellClasses: { [key: string]: boolean | Function };

  condition = (rowData: any, columnKey: string) => {
    // 'column3' 列に対してのみスタイルを付与する
    if (columnKey !== 'column3') {
      return false;
    }
    // rowData[columnKey] で 'column3' 列の値を取得
    // 値が true/false を返す
    return rowData[columnKey];
  }

  ngOnInit(): void {
    ...
    // cellClasses の初期化 
    this.cellClasses = {
      'bordered-cell': true,
      'is-true': this.condition
    };
    // 列定義の生成
    this.columns = Object.entries(this.data[0]).map(([key, value], index) => {
      ...
      return {
        field: key,
        header: key.toUpperCase(),
        dataType,
        width: 100 + (index % 5) * 50,
        // CSSクラスのセット
        cellClasses: this.cellClasses,
        ...
      };
    });
  }
```
TypeScript 側に `cellClasses` というプロパティを用意して（どんな名前でもOK）、`ngOnInit()` で初期化しています。このとき、ある条件に合致したセルにのみ `is-true` というCSSクラスを付与したいので 、`condition` という関数をセットしています。`condition` 関数は引数を2つとります。

- rowData: 行のデータ
- columnKey: 列のキー

これらの情報を使って、条件付きセルスタイリングを実現することができます。

html テンプレート側では、`[cellClasses]="column.cellClasses"` としてバインドするだけです。

```html:app.component.html
    <igx-column *ngFor="let column of columns"
                [field]="column.field"
                [header]="column.header"
                [dataType]="column.dataType"
                [width]="column.width"
                [cellClasses]="column.cellClasses"
                ...>
    </igx-column>
```

最後に`is-true`クラスの実装です。

```scss:app.component.scss
:host::ng-deep {
  .bordered-cell {
    border-right: 1px solid rgba(0, 0, 0, .08); 
  }
  .is-true {
    background-color: lightpink;
  }
}
```

実際に出来上がったデモはこちらです。
https://stackblitz.com/edit/igx-grid-styling

`COLUMN3` の値が `true` であるセルだけ背景色を変更することができました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/70618/db0dfdd3-ef07-cad2-b904-7dfd288fdc9e.png)
条件付きスタイリングは、値が後から変更になった場合も機能します。このデモ上で `COLUMN3`列のセルをダブルクリックして `false -> true/true -> false` に変更してみると、値の変更に伴って、スタイルも瞬時に変わることが確認できます。

## 奇数行と偶数行で背景色を変えたい
いわゆるストライプテーブルというやつですが、`igx-grid` が持っている `oddRowCSS`、`evenRowCSS` というプロパティを使って実現することができます。

- `oddRowCSS`: 奇数行に適用するCSS
- `evenRowCSS`: 偶数行に適用するCSS

```html:
  <igx-grid [data]="data"
            ...
            [oddRowCSS]="'odd-row'"
            [evenRowCSS]="'even-row'"
            ...
            >
    ...
  </igx-grid>
```

```scss:app.component.scss
:host::ng-deep {
  .odd-row {
    background-color: lightblue;
  }
  .even-row {
    background-color: lightgreen;
  }
}
```

## 列ヘッダーの色を変更したい
`igx-column` に [headerClasses](https://jp.infragistics.com/products/ignite-ui-angular/docs/typescript/classes/igxcolumncomponent.html#headerclasses) というプロパティがあり、列ヘッダーに任意のCSSクラスを追加することができます。

`headerClasses` は `cellClasses` と異なり string のみを受け入れます。

列定義を動的に生成しているので、列に応じて異なるCSSクラスをセットすることも可能です。例えば以下のように `header{index % 3}` として、`header0/header1/header2` を順にセットしています。

```typescript:app.component.ts
export class AppComponent implements OnInit {
  ...

  ngOnInit(): void {
    ...
    // 列定義の生成
    this.columns = Object.entries(this.data[0]).map(([key, value], index) => {
      ...
      return {
        field: key,
        header: key.toUpperCase(),
        dataType,
        width: 100 + (index % 5) * 50,
        // CSSクラスのセット
        cellClasses: this.cellClasses,
        // ヘッダーへのCSSクラスのセット
        headerClasses: `header{index % 3}`,
        ...
      };
    });
  }
```

html テンプレート側では、`[headerClasses]="column.headerClasses"` としてバインドするだけです。

```html:app.component.html
    <igx-column *ngFor="let column of columns"
                [field]="column.field"
                [header]="column.header"
                [dataType]="column.dataType"
                [width]="column.width"
                [cellClasses]="column.cellClasses"
                [headerClasses]="column.headerClasses"
                ...>
    </igx-column>
```

最後に `header0/header1/header2` クラスの実装です。

```scss:app.component.scss
:host::ng-deep {
  .header0 {
    background-color: #0ee;
  }
  .header1 {
    background-color: #ee0;
  }
  .header2 {
    background-color: #e0e;
  }
}
```

結果は以下のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/70618/feb32dbf-7372-3be7-6a3a-e4e595a1199a.png)

## まとめ
### `igx-column` にあるプロパティ

|プロパティ|説明|
|---|---|
|cellClasses|セルに適用できるCSSクラス<br>Object 型を受け入れる<br>条件付きスタイリングも可能|
|headerClasses|列ヘッダーに適用できるCSSクラス<br>string 型を受け入れる|

### `igx-grid` にあるプロパティ

|プロパティ|説明|
|---|---|
|oddRowCSS|奇数行に適用できるCSSクラス<br>string 型を受け入れる|
|evenRowCSS|偶数行に適用できるCSSクラス<br>string 型を受け入れる|

上記のように、スタイリングを行うためのプロパティはいくつかありますが、柔軟にセルのスタイリングを行える `igx-column` の `cellClasses` が一番使用頻度が高いかと思います。

## Ignite UI for Angular が気になった方はこちら
デモサイトで様々なサンプルを試すことができるので色々試してみてください！
https://jp.infragistics.com/products/ignite-ui-angular/angular/components/grid_virtualization.html