インフラジスティックス・ジャパン株式会社Blog

インフラジスティックス・ジャパン株式会社のチームメンバーが技術トレンド、製品Tips、サポート情報からライセンス、日々の業務から感じることなど、さまざまなトピックについてお伝えするBlogです。

Blazor アプリ上で Excel ライクなスプレッドシートを実現する

Blazor アプリケーションの開発時に、Excel ライクなスプレッドシートを実現したい、ということはありませんか? インフラジスティックスが提供するクライアント Web アプリケーション向けコンポーネント製品 Ignite UI for jQuery を活用すると、Blazor アプリケーション上でも Excel ライクなスプレッドシートを実装できます!

このブログ記事では、以下のような Excel ライクなスプレッドシートをページ上に備えた Blazor アプリケーションを、Ignite UI for jQuery を用いて実装する方法をご案内します。

Ignite UII for jQuery を使用する準備

まずは準備として、新規の Blazor WebAssembly アプリケーションプロジェクトを作成しておきます。もちろん、Blazor Server でも同様の手順で実現可能ですが、このブログ記事では Blazor WebAssembly で話を進めていきます。

さて、Ignite UI for jQuery ですが、こちらは JavaScript および CSS ファイルで提供される、JavaScript ライブラリの形態となります。トライアル版を CDN から参照して試用してみましょう。

Blazor WebAssembly アプリケーションプロジェクト中、wwwroot/index.html を開いて、必要な JavaScript および CSS ファイルへの参照を、以下のように追加します。

<!-- wwwroot/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    ...
    <!-- 以下の CSS ファイル x 2 本を参照 -->
    <link rel="stylesheet" href="https://cdn-na.infragistics.com/igniteui/2023.2/latest/css/themes/infragistics/infragistics.theme.css" />
    <link rel="stylesheet" href="https://cdn-na.infragistics.com/igniteui/2023.2/latest/css/structure/infragistics.css" />
</head>

<body class="ig-typography">
    ...
    <script src="_content/IgniteUI.Blazor/app.bundle.js"></script>
    <script src="_framework/blazor.webassembly.js"></script>

    <!-- 以下の JavaScript ファイル x 7 本を参照 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
    <script src="https://cdn-na.infragistics.com/igniteui/2023.2/latest/js/infragistics.core.js"></script>
    <script src="https://cdn-na.infragistics.com/igniteui/2023.2/latest/js/infragistics.lob.js"></script>
    <script src="https://cdn-na.infragistics.com/igniteui/2023.2/latest/js/infragistics.excel-bundled.js"></script>
    <script src="https://cdn-na.infragistics.com/igniteui/2023.2/latest/js/infragistics.spreadsheet-bundled.js"></script>

</body>
</html>

これで、Ignite UI for jQuery によるスプレッドシート機能に関する様々な JavaScript 関数が呼び出せるようになりました。

Ignite UI for jQuery の使い方

Ignite UI for jQuery のスプレッドシートコンポーネントの使い方 (JavaScript プログラムとなります) は以下のようになります。

指定した DOM 要素をスプレッドシート化する

まず、DOM 要素を指定して igSpreadsheet メソッドを呼び出すと、もうそれだけで、その指定した要素がスプレッドシートになって出現します!

$(element).igSpreadsheet({width: "100%", height: "100%"});

Excel ワークブック (.xlsx) をスプレッドシートに読み込ませる

Excel ワークブック (.xlsx) をこのスプレッドシートに読み込ませるには、いくつか方法がありますが、例えば Excel ワークブック (.xlsx) の内容が UInt8Array の byte 配列の表現で渡される場合、以下のように、Workbook オブジェクトに読み込んで、それをスプレッドシートの "workbook" という名前のオプションに設定することで実現します。

// buff は、.xslx の内容が収められた UInt8Array
const workbook = await new Promise((resolve, reject) => 
    $.ig.excel.Workbook.load(buff, resolve, reject));
$(element).igSpreadsheet("option", "workbook", workbook);

スプレッドシートの内容を Excel ワークブック (.xlsx) として取得する

スプレッドシートの内容を Excel ワークブック (.xlsx) の byte 配列 (UInt8Array) で取得するにはこの逆を行ないます。つまり、スプレッドシートの "workbook" という名前のオプションを取得すると、それが Workbook オブジェクトなので、その Workbook オブジェクトの save メソッドを使うと、UInt8Array に書き出すことができます。

// buff に .xlsx の内容が UInt8Array で取得される
const workbook = $(element).igSpreadsheet("option", "workbook");
const buff = await new Promise((resolve, reject) => 
    workbook.save({ type: 'uint8array' }, resolve, reject));

Blazor から Ignite UI for jQuery のスプレッドシートを呼び出す

Ignite UI for jQuery のスプレッドシートを Blazor のコンポーネントとしてラップする

Ignite UI for jQuery のスプレッドシートコンポーネントの扱い方がわかってきましたので、それでは Blazor 側から使ってみることにしましょう。

まずは SpreadSheet.razor という名前で Razor コンポーネントファイルをプロジェクトに追加します。この SpreadSheet Razor コンポーネントを、Ignite UI for jQuery のスプレッドシートコンポーネントに対するラッパーとすることにします。さらに SpreadSheet.razor.js という名前で JavaScript ファイルも追加します。この SpreadSheet.razor.js 内に、Blazor 側からの指示を Ignite UI for jQuery 側に中継する JavaScript 関数を実装していきます。

早速、SpreadSheet.razor.js をエディタで開き、引数に指定された要素をスプレッドシート化する関数を Blazor 側に公開しましょう。以下のように initialize JavaScript 関数を実装します。

export const initialize = (element, options) => {
    $(element).igSpreadsheet(options);
}

次は SpreadSheet.razor です。 Blazor の JavaScript 相互運用呼び出しを使いますので、そのためのサービスオブジェクト、IJSRuntime オブジェクトを DI コンテナから注入してもらうように @inject ディレクティブを記述します。

<!-- SpreadSheet.razor -->
@inject IJSRuntime JSRuntime

続けて、スプレッドシート化する div 要素をマークアップし、また、その div 要素を先の JavaScript 関数に渡してスプレッドシート化するために、その div 要素への ElemenetReference 参照を取得するようにします。

<!-- SpreadSheet.razor -->
@inject IJSRuntime JSRuntime

<div @ref="_spreadsheet"></div>

@code {
  ElementReference _spreadsheet;
}

そして、この SpreadSheet Razor コンポーネントの初回描画完了時に、先に実装した initialize JavaScript 関数を、スプレッドシート化する用の div 要素への参照を引数に指定して呼び出します。

<!-- SpreadSheet.razor -->
@inject IJSRuntime JSRuntime

<div @ref="_spreadsheet"></div>

@code {
  ElementReference _spreadsheet;

  protected override async Task OnAfterRenderAsync(bool firstRender)
  {
    if (firstRender)
    {
      await using var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./SpreadSheet.razor.js");
      await module.InvokeVoidAsync("initialize", _spreadsheet, new { Width = "100%", Height = "100%"});
    }
  }
}

以上で Ignite UI for jQuery のスプレッドシートを、Razor コンポーネントにラップすることができました。この SpreadSheet Razor コンポーネントを、例えば App.razor などでマークアップすると...

<!-- App.razor -->
<SpreadSheet></SpreadSheet>

そこにスプレッドシートが出現するようになります!

Excel ワークブックのアップロード・ダウンロード機能を、メソッドとして公開

続けて、このスプレッドシートへの、Excel ワークブック (.xlsx) のアップロードとダウンロードも実装してみましょう。

まずは SpreadSheet.razor.js に、アップロード (load) とダウンロード (save) を行なう中継用の JavaScript 関数を次のように実装します。

// 引数に、スプレッドシート要素と、UInt8Array で .xslx を与える
export const load = async (element, buff) => {
  const workbook = await new Promise((resolve, reject) =>
    $.ig.excel.Workbook.load(buff, resolve, reject));
  $(element).igSpreadsheet("option", "workbook", workbook);
}

// 引数にスプレッドシート要素を与えると、その内容 (.xlsx) が UInt8Array で戻り値に返る
export const save = async (element) => {
  const workbook = $(element).igSpreadsheet("option", "workbook");
  const buff = await new Promise((resolve, reject) =>
    workbook.save({ type: 'uint8array' }, resolve, reject));
  return buff;
}

次は Blazor 側です。上記で用意した load および save JavaScript 関数を呼び出すメソッドを、Blazor 側、SpreadSheet コンポーネントから public メソッドとして公開しましょう。Excel ワークブック (.xlsx) の内容は byte 配列でやりとりします。

<!-- SpreadSheet.razor -->
...
@code {
  ...
  public async ValueTask LoadAsync(byte[] data)
  {
    await using var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./SpreadSheet.razor.js");
    await module.InvokeVoidAsync("load", _spreadsheet, data);
  }

  public async ValueTask<byte[]> SaveAsync()
  {
    await using var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./SpreadSheet.razor.js");
    var data = await module.InvokeAsync<byte[]>("save", _spreadsheet);
    return data;
  }
}

SpreadSheet Razor コンポーネント側はこれで完了です。

使ってみる

それではこの SpreadSheet Razor コンポーネントを使う側を実装してみましょう。

Excel ワークブックのアップロード

まずはアップロードから。Blazor 標準のファイル選択コンポーネント InputFile コンポーネントを配置し、その OnChange イベントをハンドルすることで、ファイル選択で選択されたファイルの内容を byte[] 配列に読み取ることができます。あとは SpreadSheet コンポーネントに先に実装した LoadAsync メソッドに、その byte 配列を渡せば良いです。なお、SpreadSheet Razor コンポーネントのメソッドを呼び出すには、その参照が必要になりますので、@ref ディレクティブで参照を取得するようにしておきます。

<!-- App.razor -->
<InputFile OnChange="OnFileSelected" accept=".xlsx" />

<SpreadSheet @ref="_spreadshet"></SpreadSheet>

@code 
{
  SpreadSheet? _spreadsheet;

  // InputFile でファイルが選択されると呼び出される
  private async Task OnFileSelected(InputFileChangeEventArgs e)
  {
    if (_spreadsheet is null) return;

    // InputFile で選択されたファイルを byte 配列に読み取り、
    var buff = new byte[e.File.Size];
    using var stream = e.File.OpenReadStream();
    await stream.ReadAsync(buff, 0, (int)e.File.Size);

    // 読み取った byte 配列を SpreadSheet に渡して読み込ませる
    await _spreadsheet.LoadAsync(buff);
  }
}

Excel ワークブックのダウンロード

ダウンロードはもっと簡単です。ダウンロードを行なうためのボタンを配置し、そのボタンがクリックされたら先に実装した SaveAsync メソッドを呼び出して、スプレッドシートの内容 (.xlsx) を byte 配列で取得します。

今回はデモンストレーションとして、取得した byte 配列をファイルとしてブラウザにダウンロードさせるようにしてみます。なお、byte[] 配列をブラウザにダウンロードさせるには、Blazor の標準機能では足りません。そこで今回は、JavaScript 相互運用呼び出しを拡張する NuGet パッケージを使用します。そのため、IJSRuntime サービスオブジェクトを @inject で注入しておきます。実装は以下のようになります。

<!-- App.razor -->
@inject IJSRuntime JSRuntime

...

<IgbButton @onclick="OnClickDownload">
  ダウンロード
</IgbButton>

<SpreadSheet @ref="_spreadshet"></SpreadSheet>

@code 
{
  SpreadSheet? _spreadsheet;

  private async Task OnFileSelected(InputFileChangeEventArgs e)
  {
    ...
  }

   // [ダウンロード] ボタンがクリックされると呼び出される
  private async Task OnClickDownload()
  {
    if (_spreadsheet is null) return;

    // SpreadSheet の内容を .xlsx 形式の byte 配列で取得
    var data = await _spreadsheet.SaveAsync();

    // 取得した byte 配列を .xlsx 形式でブラウザにダウンロード
    await JSRuntime.InvokeDownloadAsync("spreadsheet.xlsx", "application/vnd.ms-excel", data);
  }
}

以上で、冒頭で示したとおりの、Excel ライクなスプレッドシートを備える Blazor アプリケーションが完成しました!

まとめ

このように Ignite UI for jQuery と組み合わせることで、Blazor アプリケーション上でも Excel ライクなスプレッドシートを実現することができます。このブログ記事では、Ignite UI for jQuery のスプレッドシートを Blazor の Razor コンポーネントとしてラップしましたので、これを利用する側は、Blazor の構文のみで、Excel ワークブック (.xlsx) をこのスプレッドシートに読み込ませたり、取得したりすることができるようになりました。

Ignite UI for jQeury には他にも様々な機能が公開されており、Blazor からは JavaScript 相互運用機能を経由してそれらを呼び出すことで、より高度な利用も可能です。

このブログ記事で実装した Blazor アプリケーションのソースコードは、さらに内容を整理の上、以下の GitHub リポジトリで公開していますので、ぜひ試してみてください。

github.com

実際に動作するライブデモサイトも、こちらの URL (https://igjp-sample.github.io/SpreadSheetOnBlazor/) で公開しています。

なお、Ignite UI for jQuery のライセンスをまだお持ちでない場合は、試用版の利用申し込みが必要です。以下のリンク先からどうぞ。

jp.infragistics.com

リンク: Ignite UI for Blazor について