Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

JavaScriptスプレッドシート部品「SpreadJS」と入力フォーム部品「InputManJS」をReact環境で活用

  • LINEで送る
  • このエントリーをはてなブックマークに追加

 本記事では、グレープシティが提供するJavaScriptスプレッドシート部品「SpreadJS(スプレッドJS)」と、入力フォーム部品「InputManJS(インプットマンJS)」を、JavaScriptライブラリReactと組み合わせて利用する方法を紹介します。SpreadJSやInputManJSを、Reactとシームレスに連携して活用できます。

はじめに

 「SpreadJS(スプレッドJS)」はグレープシティのJavaScriptスプレッドシート部品、「InputManJS(インプットマンJS)」は入力フォーム部品で、いずれも2018年にアップデートされました。各ライブラリの概要やアップデート内容は過去記事(SpreadJSInputManJS)も参考にしてください。

 これらのライブラリでは、AngularReactVue.jsといったJavaScriptフレームワークやライブラリとの組み合わせが想定されています。本記事では、これらのうちReactとの組み合わせについて、実装方法を紹介します。SpreadJSやInputManJSのコントロールをReactのコンポーネントとして利用できます。

対象読者

  • React環境で、多機能なUI部品を利用したい方
  • SpreadJSやInputManJSを使いつつ、それ以外のJavaScript実装も楽に行いたい方
  • 商用JavaScriptライブラリの利用に興味があるReactユーザーの方

必要な環境

 SpreadJSやInputManJSがサポートするブラウザは「Internet Explorer 11、Microsoft Edge、Chrome、Safari 5.1以上、Firefox、iOS(Safari、Chrome)」です。詳細はそれぞれの公式ページ(SpreadJSInputManJS)を参照してください。

 Reactでは、プロジェクトを生成する「create-react-app」ツールが利用できます。ツールの動作にはNode.jsが必要です。

 以上を踏まえて、今回は以下の環境で動作を確認しています。

  • Windows 10 64bit版
    • SpreadJS V11J
    • InputManJS V2J
    • React 16.6.3
    • Node.js v10.14.1 64bit版
    • Microsoft Edge 44.17763.1.0

 サンプルコードを実行するには、プロジェクトのフォルダーで「npm install」コマンドを実行してライブラリをダウンロード後、「npm start」コマンドを実行します。なお、InputManJSを利用するサンプルでは、公式ページからダウンロードできるトライアル版の圧縮ファイルから、React用の追加ファイルをプロジェクトのsrc/inputmanjsフォルダーに配置する必要があります(詳細は後述)。

 サンプルコードはトライアル版として実行されます。正式版ライセンスの設定方法は公式ページを参照してください。

Reactの概要とサンプルプロジェクトの生成

 Reactは、Facebook社とオープンソースコミュニティで開発されているJavaScriptライブラリです。詳細はWijmo+Reactの解説記事や、CodeZineの連載記事「基礎からはじめるReact入門」を参照してください。

 Reactのプロジェクトを生成して実行するには、リスト1のコマンドを実行します。生成されたプロジェクト(p001-default)をサンプルコードに含めています。

リスト1 Reactのプロジェクトを生成して実行するコマンド
npx create-react-app p001-default # プロジェクト生成 ...(1)
cd p001-default                   # プロジェクトフォルダーに移動 ...(2)
npm start                         # プロジェクト実行 ...(3)

 このプロジェクトをベースに修正して、SpreadJSやInputManJSを組み込んでいきます。

ReactプロジェクトにSpreadJSを組み込む

 ReactプロジェクトでSpreadJSのスプレッドシート(Spread.Sheets)を表示させる方法を、図1のサンプルで説明します。スプレッドシートの内容を変更すると、下部のテーブルに変更内容が反映されます。

図1 ReactでSpread.Sheetsを表示するサンプル(p002-spreadsheets)
図1 ReactでSpread.Sheetsを表示するサンプル(p002-spreadsheets)

 最初に、リスト2のコマンドを実行して、Spread.Sheetsと日本語リソースをプロジェクトに追加します。コマンド末尾で「@11.2.4」とバージョンを指定しているのは、npm(Node.jsのパッケージマネージャー)に登録されているSpread.Sheetsの最新バージョンが、記事執筆時点で国内向けに提供されているバージョンより新しいためです。

リスト2 プロジェクトにSpread.Sheetsを追加するコマンド
npm install @grapecity/spread-sheets-react@11.2.4        # Spread.Sheets
npm install @grapecity/spread-sheets-resources-ja@11.2.4 # 日本語リソース

 日本語リソースは、Webページ表示時に最初に実行されるindex.jsで、リスト3の通り設定します。(1)でSpread.Sheetsと日本語リソースをインポートして、(2)で言語を日本語(ja-jp)に設定します。

リスト3 日本語リソースの設定(p002-spreadsheets/src/index.js)
// Spread.Sheetsと日本語リソースをインポート ...(1)
import * as GC from '@grapecity/spread-sheets';
import '@grapecity/spread-sheets-resources-ja';
// 言語を日本語に設定 ...(2)
GC.Spread.Common.CultureManager.culture('ja-jp');

 次に、画面表示に対応するAppコンポーネント(App.js)の先頭にリスト4の通り記述して、Spread.SheetsのCSSファイルやコンポーネントをインポートします。

リスト4 Spread.Sheetsをインポートする記述(p002-spreadsheets/src/App.js)
import '@grapecity/spread-sheets/styles/gc.spread.sheets.excel2013white.css';
import { SpreadSheets, Worksheet, Column } from '@grapecity/spread-sheets-react';

 Appクラスのコンストラクターはリスト5の通り実装します。

リスト5 Appクラスのコンストラクター(p002-spreadsheets/src/App.js)
constructor(props) {
  super(props);
  // スプレッドシートに表示するデータ ...(1)
  this.data = [
    { 'vendor': 'Apple', 'name': 'iPhone XS', 'os': 'iOS' },
(略)
  ];
  // データをstateに設定 ...(2)
  this.state = {
    data: this.data
  };
  // スプレッドシートの表示設定(サイズと枠線) ...(3)
  this.hostStyle = {
    width: '600px', height: '200px', border: '1px solid black'
  };
  // メソッドをthisにバインド ...(4)
  this.spreadSheetsValueChanged = this.spreadSheetsValueChanged.bind(this);
}

 スプレッドシートに表示するデータを(1)に記述します。データはvendor(メーカー)、name(製品名)、os(OS)のキーを持つJavaScriptオブジェクトの配列です。このデータを、(2)でReactのstate(内部状態)に設定します。

 (3)のhostStyleはスプレッドシートの表示設定です。ここでは表示サイズと、周辺の枠線の設定を記述します。(4)は、後述するイベント処理内で、Appクラス自身をthisとして参照できるようにする処理です。

 Reactでコンポーネントの表示内容を記述するrenderメソッドは、リスト6の通り記述します。Reactでは、HTMLタグによく似たJSXと呼ばれる記法で、コンポーネントの表示内容を記述できます。

リスト6 renderメソッドの実装(p002-spreadsheets/src/App.js)
render() {
  return (
    <div>
      <h3>Spread.Sheetsでの表示</h3>
      {/* SpreadSheets:スプレッドシート ...(1)*/}
      <SpreadSheets hostStyle={this.hostStyle}
        valueChanged={this.spreadSheetsValueChanged}>
        {/* WorkSheet:ワークシート ...(2)*/}
        <Worksheet name="2018冬" dataSource={this.state.data}>
          {/* Column:列 ...(3) */}
          <Column dataField="vendor" width="100" headerText="メーカー"/>
          <Column dataField="name" width="150" headerText="製品名"/>
          <Column dataField="os" width="100" headerText="OS"/>
        </Worksheet>
      </SpreadSheets>
(略:データを表示するテーブル)
    </div>
  )
}

 (1)の<SpreadSheets>タグは、スプレッドシート全体を表します。hostStyleに、リスト5(3)で定義したthis.hostStyleを設定します。また、スプレッドシート変更時のイベントvalueChangedに、this.spreadSheetsValueChangedメソッド(後述)を設定します。

 (2)の<Worksheet>タグは、1つのワークシートを表します。ここではシート名をnameに、リスト5(2)でstateに設定したデータをdataSourceに設定します。

 (3)の<Column>タグは、シート内の各列を表します。表示させるデータのキーをdataFieldに指定します。ここではそのほかにwidth(列幅)、headerText(ヘッダー行の文言)を設定しています。

 スプレッドシート変更時に実行されるspreadSheetsValueChangedメソッドは、リスト7の通り実装します。

リスト7 スプレッドシート変更時の処理(p002-spreadsheets/src/App.js)
spreadSheetsValueChanged(e, info) {
  this.data[info.col][info.row] = info.newValue; // dataを更新 ...(1)
  this.setState({
    data: this.data // dataの変更を画面に反映 ...(2)
  });
}

 メソッドの第1引数eにイベントの種類(「valueChanged」など)、第2引数infoには変更内容が渡されます。ここでは、変更された行・列番号と変更後の値をinfoから取得して(1)でdataを更新後、そのデータを(2)でstateに設定して画面に反映させます。

ReactプロジェクトにInputManJSを組み込む

 ReactプロジェクトにInputManJSを組み込む方法を、図2のサンプルで説明します。このサンプルでは、各コントロールに入力した値が、コントロール直下に表示されます。

図2 ReactでInputManJSコントロールを表示するサンプル(p003-inputmanjs)
図2 ReactでInputManJSコントロールを表示するサンプル(p003-inputmanjs)

 最初に、リスト8のコマンドを実行して、プロジェクトにInputManJSを追加します。

リスト8 プロジェクトにInputManJSを追加するコマンド
npm install @grapecity/inputman

 リスト8のコマンドで追加されるのはInputManJSの本体だけなので、React対応に必要な追加のJavaScriptファイルを、InputManJSの圧縮ファイルに含まれるReactサンプルから抽出して、src/inputmanjsフォルダーに図3の通り配置します。

図3 InputManJSのReact用追加ファイルを配置(p003-inputmanjs)
図3 InputManJSのReact用追加ファイルを配置(p003-inputmanjs)

 Appコンポーネント(App.js)では、リスト9の通りInputManJSをインポートします。

リスト9 InputManJSをインポートする記述(p003-inputmanjs/src/App.js)
import '@grapecity/inputman/CSS/gc.inputman-js.css';
import { GcTextBox, (略) } from './inputmanjs/GcInputMan.component';

 Spread.Sheetsの場合と同様に、コンストラクター(初期化処理)とrenderメソッド、コントロールの変更時にstateを更新するメソッドを実装します。ここでは、テキストコントロール(GcTextBox)に関連した実装をリスト10に抽出して説明します。

リスト10 テキストコントロールを表示する実装(p003-inputmanjs/src/App.js)
// コンストラクター ...(1)
constructor(props) {
  super(props);
  // コントロールの初期値をstateに設定
  this.state = {
    textValue: 'テキスト'
  };
  // メソッドのバインド
  this.textControlChanged = this.textControlChanged.bind(this);
}
// 表示処理 ...(2)
render() {
  return (
    <div>
      <h3>テキストコントロール</h3>
      <GcTextBox text={this.state.textValue}
        onTextChanged={this.textControlChanged} />
      <div>{this.state.textValue}</div>
    </div>
  );
}
// テキストコントロール変更時の処理 ...(3)
textControlChanged(value) {
  this.setState({ textValue: value });
}

 (1)のコンストラクターで、stateへの初期値設定と、変更時に実行されるメソッドのバインドを行います。(2)のrenderメソッドでは、<GcTextBox>タグでテキストコントロールを記述します。stateに設定された文字列(this.state.textValue)をtextに、変更時のメソッド(this.textControlChanged)をonTextChangedに設定します。変更時に実行される(3)のメソッドでは、引数valueで渡される変更後の値でstateを更新します。

 GcTextBox以外のInputManJSコントロールについても、実装の流れは同様です。詳細はサンプルコードを参照してください。

Spread.SheetsとInputManJSをReact上で連携させる

 応用例として、Reactに組み込んだSpread.SheetsとInputManJSを、React上で連携させるサンプル(図4)を説明します。フォームに代表者名と人数を入力して反映ボタンをクリックすると、入力内容がスプレッドシートに追記されます。なお、人数欄の数値コントロールには、「人」の接尾辞や数値の範囲(1~10)を設定しています。詳細はサンプルコードを参照してください。

図4 Spread.SheetsとInputManJSを連携させるサンプル(p004-combination)
図4 Spread.SheetsとInputManJSを連携させるサンプル(p004-combination)

 サンプルの要点を以下で説明します。まず、Appクラスのコンストラクターでは、リスト11の通りstateを初期設定します。(1)と(2)がInputManJSのコントロール、(3)がSpread.Sheetsのスプレッドシートに表示されます。なお、(3)には1件分のデータを初期設定しています。

リスト11 stateの初期設定(p004-combination/src/App.js)
this.state = {
  personName: '',  // テキストコントロール(代表者)の値 ...(1)
  personCount: 1,  // 数値コントロール(人数)の値 ...(2)
  data: [          // Spread.Sheetsに表示する値 ...(3)
    {
      personName: '山田太郎',
      personCount: 2,
      logTime: new Date()
    }
  ]
};

 入力フォームの反映ボタン押下時に実行する処理は、リスト12の通りです。

リスト12 反映ボタン押下時の処理(p004-combination/src/App.js)
applyValueToSpreadSheets() {
  // 検証コントロール ...(1)
  if (!this.validator.validate()) {
    return;
  }
  // 既存データに行を追加 ...(2)
  var newData = [].concat(this.state.data, [
    {
      personName: this.state.personName,
      personCount: this.state.personCount,
      logTime: new Date()
    }
  ]);
  // state更新 ...(3)
  this.setState({
    data: newData,  // データを更新 ...(4)
    personName: '', // InputManJSコントロールを初期値に戻す ...(5)
    personCount: 1,
  });
}

 (1)で入力内容を検証後(詳細は後述)、(2)で、InputManJSコントロールの入力値と現在時刻をデータ配列(this.state.data)の末尾に追加した新しいデータ配列newDataを作成します。(3)はstate更新処理で、(4)でnewDataを設定してSpread.Sheetsを更新する一方、(5)でInputManJSコントロールを初期値に戻してフォームを初期化します。

 図4のサンプルで利用されているSpread.SheetsやInputManJSの機能について、以下の補足も参考にしてください。

[補足]Spread.Sheetsに数式を設定

 図4のサンプルでは、スプレッドシートの1行目右端に「累積人数」が表示されます。この処理は、リスト13の処理でセルに数式を設定して実現しています。

リスト13 Spread.Sheetsセルへの数式設定(p004-combination/src/App.js)
<SpreadSheets workbookInitialized={this.spreadSheetsWorkbookInitialized}>
(略)
spreadSheetsWorkbookInitialized(spread) {
  if (spread) {
    var sheet = spread.getActiveSheet(); // ワークシートを取得 ...(1)
    sheet.setFormula(0, 3, '=sum(C:C)'); // C列の合計を表す数式を設定 ...(2)
  }
}

 ワークシート初期化後に実行されるSpreadSheetsタグのworkbookInitializedイベントに設定したthis.spreadSheetsWorkbookInitializedメソッド内で、スプレッドシートに対応するspread変数から、(1)でワークシートを取得して、(2)のsetFormulaメソッドで(0, 3)=1行4列目のセルに、C列(人数)の合計値に対応する数式を設定します。

[補足]Spread.SheetsのautoGenerateColumns設定

 図4のサンプルでは、Spread.Sheetsの<WorkSheets>タグで、autoGenerateColumnsをfalseに設定しています。

リスト14 図4のサンプルの<WorkSheet>タグ(p004-combination/src/App.js)
<Worksheet name="来訪者"
  dataSource={this.state.data} autoGenerateColumns={false}>
  <Column (略)/>
(略)
</Worksheet>

 autoGenerateColumnsは、データ設定時に列を自動的に生成する設定です。デフォルトのtrueでは、setStateメソッドでデータが更新されてSpread.Sheetsに設定されるたび、<Column>タグで記述した列が消えて列が再生成されるため、最初に指定した列幅の設定が消えてしまいます。このサンプルではデータ更新時に列幅を維持するため、autoGenerateColumnsをfalseに設定しています。

[補足]InputManJSの検証コントロール

 図4のサンプルでは、代表者のテキストコントロールに、入力必須の検証コントロールを設定しています。検証コントロールは2018年10月のアップデートで追加されたInputManJSの新機能です。詳細は過去記事を参照してください。

図5 入力必須の検証コントロール(p004-combination)
図5 入力必須の検証コントロール(p004-combination)

 React環境でInputManJSの検証コントロールを利用するには、まず、検証するコントロールを参照する変数(ref)を作成します。Reactが提供するcreateRefメソッドで作成した変数を、コントロールに対応するタグのref属性に設定します(リスト15)。この場合、テキストコントロール(GcTextBox)を参照するthis.gcTextBox変数が作成されます。

リスト15 createRefによるコントロールの参照(p004-combination/src/App.js)
this.gcTextBox = React.createRef();
(略)
<GcTextBox ref={this.gcTextBox}(略)/>

 次に、AppコンポーネントがDOMツリーに追加されたときに実行されるcomponentDidMountメソッドで、リスト16の通り検証コントロールを作成します。リスト15で作成したthis.gcTextBox変数の「current.imControl」プロパティを、検証対象としてcontrolに指定します(1)。「current」はcreateRefメソッドで作成した変数から参照先を取得するReactのプロパティ、「imControl」はコントロールを取得するInputManJSのプロパティです。

リスト16 検証コントロールの作成(p004-combination/src/App.js)
componentDidMount() {
  this.validator = new InputMan.GcValidator({
    items: [
      {
        control: this.gcTextBox.current.imControl, // ...(1)
(略)
}

 ここで作成したthis.validatorを利用して、リスト12(1)で検証を行います。

まとめ

 本記事では、グレープシティのJavaScriptライブラリSpreadJSとInputManJSを、Reactと組み合わせて利用する方法を説明しました。Reactと組み合わせることで、各ライブラリのコントロールをReactのコンポーネントとして活用できます。応用として、Reactを仲立ちとして、SpreadJSとInputManJSを連携して動作させるサンプルを紹介しました。

参考資料

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5