IM-FormaDesignerのグリッドテーブルでセレクトボックスによる入力制御をかける

# 対象となる開発形態
- intra-mart Accel Platform
   - IM-FormaDesigner

# やりたいこと
IM-FormaDesignerのグリッドテーブルで、セレクトボックスの選択内容によって別の列にあるセレクトボックスを入力不可にし、入力状態をクリアする。

# Formaの機能で実現させると
1. アクション設定-テーブルイベント-通常イベントでトリガーとなるセレクトボックス列を選択する。
2. 設定でアクション「入力モード変更」で、入力不可にしたいフィールドを選択し、入力モードを入力不可にする。条件は`gt1_selectbox1="0"`のように設定。
入力モードを元に戻せるようにする場合、そのアクションも設定する。
3. アクション「カスタムスクリプト」を追加し、以下のスクリプトを貼る。
条件は入力不可にする場合と同じ。

```js
// クリックされた行IDを取得
var rowid = $(e.target).closest('tr')
                       .attr('id');
var args = {};
args.data = {};
args.data.gt1 = [];
args.data.gt1[0] = {};
var option = {};
option.indexKey = rowid;
args.data.gt1[0].gt1_selectbox2 = '';
// セレクトボックスの値を消去
formaItems.product_80_gridtable.setItemData.gt1(args, option);
```
`$(e.target)`はアクションのカスタムスクリプト内で利用できる、アクション発生元を指定するセレクタです。

グリッドテーブルに値を設定するAPIについては、以下を参照してください。
[IM-BIS for Accel Platform IM-BIS 仕様書 13. クライアントサイドスクリプトAPI](https://www.intra-mart.jp/document/library/bis/public/bis_specification/texts/spec/csjs_script.html)

## 問題点
「入力」アクションは`focusout`イベントのため、1つ目のセレクトボックスの値を選択した後、別の場所をクリックしないと入力モードが変更されません。
特に、入力不可から入力可に戻るような値を選択した場合、入力可のフィールドにマウスオーバーしても禁止アイコンが出てしまい、フィールドをクリックして初めて入力可能になります。ユーザ的には分かりづらい。
また、初期表示イベントの「条件」欄ではグリッドテーブルの列を指定することはできないため、編集モードでオープンした場合の制御は結局スクリプトを使って実現するしかありません。
[IM-BIS for Accel Platform IM-BIS 仕様書 1. アクション設定](https://www.intra-mart.jp/document/library/bis/public/bis_specification/texts/spec/action_setting.html#condition-settings)

そこで、Formaのアクションを使用せず、スクリプトを使って`change`イベントで制御する方法を考えてみます。

# スクリプトを利用してchangeイベントで入力モードを制御する
## サンプルコード
スクリプトアイテムを画面上に配置するか、アクション設定-初期表示イベントでカスタムスクリプトを追加し、以下のスクリプトを貼ります。

```js
// グリッドテーブル行にclickイベントを設定
var tableid = 'gt1'
$('table#' + tableid).on('click', 'table#gt1 tr.jqgrow', function() {
   // グリッドテーブルのIDを取得
   var tableid = $(this).closest('table')
                        .attr('id');

   // クリックされた行IDを取得
   var rowid = $(this).attr('id');

   // セレクトボックス1の値を取得
   var selectbox1Val = $('table#' + tableid).find('tr#' + rowid)
                                            .find('select[name="gt1_selectbox1_display"]')
                                            .val();

   // セレクトボックス2のエレメントを取得
   var elmSelectbox2 = $('table#' + tableid).find('tr#' + rowid)
                                            .find('select[name="gt1_selectbox2_display"]');

   if (selectbox1Val === '0') {
      // セレクトボックス1が0の場合、セレクトボックス2は入力不可
      elmSelectbox2.prop('disabled', true);
      elmSelectbox2.prop('readonly', true);
      elmSelectbox2.css({
         'color': 'rgb(51, 51, 51)',
         'background-color': 'rgb(255, 255, 255)',
         'border': '1px inset rgb(204, 204, 204)'
      });
   } else {
      // セレクトボックス1が0以外の場合、セレクトボックス2は入力可
      elmSelectbox2.prop('disabled', false);
      elmSelectbox2.prop('readonly', false);
      elmSelectbox2.css({
         'color': '',
         'background-color': '',
         'border': ''
      });
   }
});

// セレクトボックス1にchangeイベントを設定
var tableid = 'gt1'
$('table#' + tableid).on('change', 'select[name="gt1_selectbox1"]', function() {
   // グリッドテーブルのIDを取得
   var tableid = $(this).closest('table')
                        .attr('id');

   // クリックされた行IDを取得
   var rowid = $(this).closest('tr')
                      .attr('id');

   // セレクトボックス2のエレメントを取得
   var elmSelectbox2 = $('table#' + tableid).find('tr#' + rowid)
                                            .find('select[name="gt1_selectbox2_display"]');

   if ($(this).val() === '0') {
      // セレクトボックス1が0の場合、セレクトボックス2は入力不可
      elmSelectbox2.prop('disabled', true);
      elmSelectbox2.prop('readonly', true);
      elmSelectbox2.css({
         'color': 'rgb(51, 51, 51)',
         'background-color': 'rgb(255, 255, 255)',
         'border': '1px inset rgb(204, 204, 204)'
      });

      // セレクトボックス1が0の場合、セレクトボックス2の値をクリア
      var args = {};
      args.data = {};
      args.data[tableid] = [];
      args.data[tableid][0] = {};
      var option = {};
      option.indexKey = rowid;
      args.data[tableid][0]['gt1_new_place'] = '';
      formaItems.product_80_gridtable.setItemData[tableid](args, option);
   } else {
      // セレクトボックス1が0以外の場合、セレクトボックス2は入力可
      elmSelectbox2.prop('disabled', false);
      elmSelectbox2.prop('readonly', false);
      elmSelectbox2.css({
         'color': '',
         'background-color': '',
         'border': ''
      });
   }
});
```

## 解説

### グリッドテーブル行のclickイベント
グリッドテーブルの入力内容は、通常はテキストで行がクリックされると入力欄が表示される仕様になっています。
この時、対象行のDOM要素が書き換えられて`<input>`や`<select>`が新たに生成されてしまうため、毎回このタイミングで入力内容から入力可否を制御してやる必要があります。
グリッドテーブルの行には`jqgrow`クラスが付与されているため、`table#tableId tr.jqgrow`で取得可能です。
なお、行がクリックされるたびに入力可否を制御しているため、編集モードでオープンした場合でも初期表示イベントで制御を行う必要はなくなります。

### セレクトボックス1のchangeイベント
グリッドテーブル行の`click`イベントとほぼ同内容を、セレクトボックス1の`change`イベントとして設定しています。
違いは`$(this)`の内容が違うことと、セレクトボックス2が入力不可になる場合は値をクリアしていることだけです。
これによって、値が変わると同時に入力可否が変更されるようになります。