こんにちは。
システムアーキテクト兼フロントエンド担当のたーせるです。
最近「どうしてもシングルページアプリケーションにデータグリッドを組み込みたい」という UI 要件が持ち上がったため、Angular と Wijmo の組み合わせを採用しようと企んでいます。
このブログでもときどき取り上げていますが、Wijmo はデータグリッドやグラフ、果ては地図まで、非常に高機能で複雑なコンポーネントがひととおり揃った有償の UI ライブラリです。
特に業務アプリケーションの開発では、発注元から「Excelのような操作性」を要求されることがあり、個人的にはデータグリッドを利用するだけでも Wijmo を採用する価値があると考えています。
ただ、一部の開発メンバからは「過去に、開発中のアプリケーションに Wijmo を組み込もうとして苦労したことがある」という声も聞こえてきました。
よくよく話を聞くと、そもそも Wijmo の正しい使い方が分からず、結局見様見真似でぐちゃぐちゃな実装をしてしまった ── という苦い経験がトラウマになっている模様。
Wijmo 組み込み基本動作のおさらい
そこで今日は、初めての人でも安心して Wijmo に触れるよう、FlexGrid の基本のキホンを手を動かして学んでみようと思います。
細かい話はさておき、この記事を読み終える頃には Angular アプリケーションにベーシックなデータグリッドを組み込めるようになりますし、簡単なカスタマイズ要件であれば対応できるようになります。
特に、itemFormatter
は、セルの外観をカスタマイズするための重要なテクニックの一つですので、ぜひ覚えておきたいところです*1。
検証環境
- Angular 12.2.5
- Wijmo 2021J v2 (5.20212.812)
準備
こちらの公式記事の手順に倣って、Wijmo をセットアップしていきます。 2019年と少し古い記事ですが、2021現在でも有効な手順でした。
Angular プロジェクトの作成
Angular のプロジェクト作成方法は既知であるものとし、特に詳しい説明は行いません。
叩いたコマンドだけ掲載しておきます。
$ ng new quickstart --routing --style css
$ cd quickstart
Wijmo のインストール
ターミナルに npm install
コマンドを入力し、Wijmo をインストールします。
$ npm install @grapecity/wijmo.angular2.all
これで、試用版の Wijmo が使えるようになりました。
試用版であっても、製品版と同じようにコンポーネントを使うことができますが、実際にブラウザで動かした際に「Wijmo トライアル版」というクレジットが表示されます。
購入後にライセンスキーを設定することで、「トライアル版」の表示を消すことができます。
style.css の設定
引き続き、公式の手順に従ってチュートリアルを進めましょう。
Angular プロジェクト全体に共通で適用される style.css に、Wijmo のデフォルト CSS を読み込みます。
style.css
@import '@grapecity/wijmo.styles/wijmo.css';
恐らくここまでは、Angular で Wijmo を使ういかなるケースにおいても実施するであろう共通の手順です。
FlexGrid 初めの一歩
ここからは、Wijmo の中でも特に利用頻度の高いデータグリッドコンポーネント・ FlexGrid を Angular で利用するための手順になります。
テキストエディタで app.module.ts
を開き、WjGridModule
とカルチャをインポートしましょう。
app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; // 略 import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; // 追加 import '@grapecity/wijmo.cultures/wijmo.culture.ja'; // 追加 @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, BrowserAnimationsModule, AppRoutingModule, // 略 WjGridModule // 追加 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
これで、FlexGrid を利用するための準備が完了したので、コンポーネントに FlexGrid を組み込んでグリッドを表示させてみましょう。
まず HTML 側は、<wj-flex-grid>
タグでグリッド全体を作り、その子要素に、表示したいデータ項目の <wj-flex-grid-column>
を並べていきます。
app.component.html
<wj-flex-grid [itemsSource]="gridData"> <wj-flex-grid-column header="ID" binding="id" [width]="60"> </wj-flex-grid-column> <wj-flex-grid-column header="商品名" binding="product" [width]="200"> </wj-flex-grid-column> <wj-flex-grid-column header="受注日" binding="date" [width]="120"> </wj-flex-grid-column> <wj-flex-grid-column header="金額" binding="amount" [width]="100" format="c"> </wj-flex-grid-column> </wj-flex-grid>
続いて、グリッドにバインドするデータを TypeScript 側に記述します。
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { gridData = [ { id: 15, product: 'ピュアデミグラスソース', date: '2017/01/10', amount: 6000 }, { id: 17, product: 'だしこんぶ', date: '2017/01/08', amount: 14500 }, { id: 18, product: 'ピリカラタバスコ', date: '2017/01/12', amount: 4000 }, { id: 84, product: 'なまわさび', date: '2017/01/21', amount: 8000 } ]; }
ここまでは、公式チュートリアルとほぼ同じ手順です。
ng serve
コマンドを叩くと、データグリッドが表示されることが確認できます。
実行結果
各項目の見出しを中央揃えにする
これで最低限の簡素なグリッドを画面に表示するところまではできました。
しかしよく見ると、各項目の見出しが右寄せだったり左寄せだったりと一貫しておらず、見た目が気になる方もいるかと思います。
そこで、itemFormatter
を使って見出しを中央に揃えましょう。
app.component.html
<wj-flex-grid [itemsSource]="gridData" [itemFormatter]="itemFormatter"> <wj-flex-grid-column header="ID" binding="id" [width]="60"> </wj-flex-grid-column> <wj-flex-grid-column header="商品名" binding="product" [width]="200"> </wj-flex-grid-column> <wj-flex-grid-column header="受注日" binding="date" [width]="120"> </wj-flex-grid-column> <wj-flex-grid-column header="金額" binding="amount" [width]="100" format="c"> </wj-flex-grid-column> </wj-flex-grid>
app.component.ts
import { Component } from '@angular/core'; import { CellType, GridPanel } from '@grapecity/wijmo.grid'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { gridData = [ { id: 15, product: 'ピュアデミグラスソース', date: '2017/01/10', amount: 6000 }, { id: 17, product: 'だしこんぶ', date: '2017/01/08', amount: 14500 }, { id: 18, product: 'ピリカラタバスコ', date: '2017/01/12', amount: 4000 }, { id: 84, product: 'なまわさび', date: '2017/01/21', amount: 8000 } ]; itemFormatter = (panel: GridPanel, r: number, c: number, cell: HTMLElement) => { if (panel.cellType === CellType.ColumnHeader) { cell.style.textAlign = 'center'; } } }
itemFormatter
を設定することで、セルの描画をカスタマイズできます。
引数の panel
は GridPanel 型のデータで、これを通して当該セルを包含している FlexGrid のあらゆるデータや属性にアクセスできます。
r
, c
は、それぞれ描画対象のセルの行・列インデックスを表しており、cell
は描画対象のセルの HTML 要素そのものです。
ここでは、これから描画しようとしているセルの型が列ヘッダの場合に限って、cell
に中央揃えのスタイルを適用するコードを書いています。
以前も書きましたが、itemFormatter
は、少なくとも可視状態のセルすべてに対して逐一呼び出されるため、あまりコストの高い処理を書いてしまうとレンダリング性能に影響が出てしまいます。
実行結果
見出しが全て中央揃えになりました。
itemFormatter
の引数は型アノテーションをしっかり書くのがポイントだよ。
ふむふむ。
手を抜いて any
とかにしちゃうと、後々悪い方に効いてくるから……。
ぉぉぅ……。
カーソルを変える
続いて、FlexGrid 上のカーソル形状を Excel っぽく変えてみましょう。
HTML テンプレートに一行 [showMarquee]="true"
を追加するだけです。
app.component.html
<wj-flex-grid [itemsSource]="gridData" [showMarquee]="true" [itemFormatter]="itemFormatter"> <wj-flex-grid-column header="ID" binding="id" [width]="60"> </wj-flex-grid-column> <wj-flex-grid-column header="商品名" binding="product" [width]="200"> </wj-flex-grid-column> <wj-flex-grid-column header="受注日" binding="date" [width]="120"> </wj-flex-grid-column> <wj-flex-grid-column header="金額" binding="amount" [width]="100" format="c"> </wj-flex-grid-column> </wj-flex-grid>
実行結果
行ヘッダを非表示にする
画面の幅が狭いデバイスで表示している場合や、表示項目が多い場合など、スペースを節約するためにグリッド左端の行ヘッダを非表示にしたいケースがあります。
この場合は、HTML テンプレートに headersVisibility="Column"
を設定すると、列ヘッダのみが表示されるようになります。
app.component.html
<wj-flex-grid [itemsSource]="gridData" [showMarquee]="true" [itemFormatter]="itemFormatter" headersVisibility="Column"> <wj-flex-grid-column header="ID" binding="id" [width]="60"> </wj-flex-grid-column> <wj-flex-grid-column header="商品名" binding="product" [width]="200"> </wj-flex-grid-column> <wj-flex-grid-column header="受注日" binding="date" [width]="120"> </wj-flex-grid-column> <wj-flex-grid-column header="金額" binding="amount" [width]="100" format="c"> </wj-flex-grid-column> </wj-flex-grid>
実行結果
なお、headersVisibility
には Column
の他に、以下の定数が指定できます。
All
(デフォルト: 行ヘッダも列ヘッダも表示する)Row
(行ヘッダのみを表示し、列ヘッダが非表示になる)None
(行ヘッダも列ヘッダも非表示になる)
フィルタを追加する
最後は、データを絞り込むためのフィルタを追加してみましょう。
見出しに漏斗のようなアイコンが表示され、レコードを条件で絞り込むことができるようになります。
ここで新しいモジュールをインポートします。 app.module.ts
に WjGridFilterModule
を追加しましょう。
app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; // 略 import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; import { WjGridFilterModule } from '@grapecity/wijmo.angular2.grid.filter'; // 追加 import '@grapecity/wijmo.cultures/wijmo.culture.ja'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, BrowserAnimationsModule, AppRoutingModule, // 略 WjGridModule, WjGridFilterModule // 追加 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
続いてHTML側の修正です。<wj-flex-grid>
の直下に <wj-flex-grid-filter>
タグを追加するだけです。
app.component.html
<wj-flex-grid [itemsSource]="gridData" [showMarquee]="true" [itemFormatter]="itemFormatter" headersVisibility="Column"> <wj-flex-grid-filter></wj-flex-grid-filter> <wj-flex-grid-column header="ID" binding="id" [width]="60"> </wj-flex-grid-column> <wj-flex-grid-column header="商品名" binding="product" [width]="200"> </wj-flex-grid-column> <wj-flex-grid-column header="受注日" binding="date" [width]="120"> </wj-flex-grid-column> <wj-flex-grid-column header="金額" binding="amount" [width]="100" format="c"> </wj-flex-grid-column> </wj-flex-grid>
実行結果
見出しの部分に、フィルタ用のアイコンが表示されました。
このアイコンをクリックすると、フィルタを掛けるためのダイアログが表示されます。
まとめ
今回は、Wijmo を使ったグリッド組み込みの基本のキホンについて学びました。
次なる壁はパフォーマンスとの戦いになるのですが、まずはライブラリの正しい使い方を開発メンバ全員が正しく知ってスタートを切れることが大事かなーと思いました。
ちなみにパフォーマンスで困ることとその対策についてはこちら。
*1:同様の手法として、formatItem や、よりパフォーマンスに優れた CustomCellFactory といった別の手段がありますが、最も簡便な手段はやはり itemFormatter になります。