notebook

都内でWEB系エンジニアやってます。

ag-Gridで任意のデータをコールバックで使いたい

今回もag-Gridについて

任意のデータをコールバックで使いたいときに使える小ネタです

gridの一覧にデータを表示したときのデータを保持しておいてその値が変わったらスタイルを適用したいといった場合

  • 環境
ag-grid:18.1.2
angular: 6.1.4

f:id:swfz:20181120005603g:plain

要件としては

  • 数値が編集されたらスタイルを変更したい
  • 初期値から変わった場合のみスタイルを変えたい

ということが実現したいわけですね

実装案1 cellValueCanged

ここで考えるのはまずcellValueCahgedのコールバックでゴニョゴニョできるかなと考えるかと思います

cellValueChangedでコールバックに渡ってくるデータはoldValue,newValueがあるので行けそうな気がします

しかし、このコールバックには直近の編集前後の値のみしか渡ってきません

  • 特定セルの数値を100 -> 105
  • 特定セルの数値を105 -> 100

といった操作をした場合にあたかも変更されたものとしてスタイルが適用されてしまいます

要件の2つ目が満たせないわけですね

実装案2 cellRendererFramework + Service

  • CellRendererFrameworkを用いてコンポーネントから状態管理用のサービスを呼び出して判定を行う

具体的にはこんな感じでしょうか

  • 初期状態のデータを持つサービスを用意
  • 数値をレンダリングするだけのag-Grid用のカスタムコンポーネントを用意
  • カスタムコンポーネント上でサービスを呼び出してセルの描画の際にスタイルを適用

ただスタイルを変えたいだけなのに。。。大げさすぎる気がしますね

実装案3 contextを使ってデータを参照する

そこでcontextの出番です

contextについてはこちら

ag-Grid Features: Context Object

www.ag-grid.com

  • gridのデータを受け取った瞬間にcontextの中身を更新
  • スタイルやクラスを決めるコールバック側ではcontextの中の値を使って変更がされているのか判断

これだけです

実際のコードはこんな感じ

  • component.ts(一部抜粋)
import _ from 'lodash';

ngOnInit() {
  this.gridOptions = <GridOptions>{};
  this.columnDefs = [
      .....
      .....
      .....
    {
      headerName: 'price',
      field: 'price',
      width: 100,
      // contextに持っているデータと比較して変化がある場合はスタイルを適用させる
      cellClassRules: {
        'bg-danger': params => {
          const nodeId = params.node.id;
          const field = params.colDef.field;
          return params.value != params.context.rowData[nodeId][field];
        },
      },
      editable: true
    }
  ];

  this.rowData = [
    {
      price: 100
    },
    {
      price: 200
    }
  ];

  // データがセットされた状態を保存
  this.gridOptions.context = { rowData: _.cloneDeep(this.rowData) }; 
}
  • component.html
<ag-grid-angular #sampleGrid
                 class="ag-theme-balham grid"
                 [gridOptions]="gridOptions"
                 [rowData]="rowData"
                 [columnDefs]="columnDefs"
                 (cellValueChanged)="valueChanged($event)">
</ag-grid-angular>

感想

contextにデータ入れとけば色んな所で使えるよっていう感じのあれです

グローバル変数的な感じですね

こういうのって便利便利で使っているとあっという間に肥大化してデバッグができなくなっていくので

  • 基本参照のみにする
    • コールバック内で書き換えを行わない
  • 多用しない
    • 他の手段で代替出来ないか調べる

など気をつける必要はありそうだなと思いました

ag-Gridのドキュメントは一応さらっと読んだのである程度何ができるか把握しているつもりだったのですが全然まだまだだったようです

結局必要にならないと真剣に調べられないんだろうなーとしみじみ感じましたがこれからも精進していく所存ですw