とりあえず書きなぐる

とりあえず、マイノリティーなプログラムを極力説明せずに書きなぐります

HandsonTableの編集にも手を出しておく

f:id:vzc00525:20190509220103p:plain
HandsonTableは標準で優れた編集機能を有しています
カラムの設定時にreadOnly:trueとすれば正にEXCELライクな編集機能が手に入ります
引っかかることもさくサックサクに動きます
エディタも色々と用意されており、もうお腹いっぱいです

ここでは編集開始のイベントでエディタの代わりにPopup等を使用して編集機能を作成してみます
先にデータクラスに数量を追加します(抜けてました)
/Sec/app.ts

namespace App {
    /*
     * テーブルに表示するデータクラス
     */
    export class TableData {

        ....

        quantity = 0;

        ....

    }
    export function duildTableData(): TableData[] {
        let dts: TableData[] = [];

        for (let i = 0; i < 100; i++) {
            let dt = new TableData;

            ....

            dt.quantity = i + 1; // 適当に値設定

            ....

            dts.push(dt);
        }
        return dts;
    }

カラム設定で編集を有効にします
/Src/table.ts

function getColumns(): Object[] {
    return [
        {
            type: "text"
            //, title: "番号" // colHeaderで設定する場合は設定しない
            , data: "data_no"
            , readOnly: false             // 編集可とするカラムのみfalse設定
            , colWidths: 100
            , editor: CustomEditor   // 作成するカスタムエディタ名
        }
        , {
            type: "text"
            //, title: "状態"
            , data: "data_state"
            , readOnly: false
            , colWidths: 100
            , renderer: htmlRenderer
            , editor: CustomEditor
        }
        , {
            type: "text"
            //, title: "日付"
            , data: "data_date"
            , readOnly: false
            , colWidths: 100
            , editor: CustomEditor
        }
        , {
            type: "text"
            //, title: "名称"
            , data: "data_name"
            , readOnly: false
            , colWidths: 300
            , editor: CustomEditor
        }
        , {
            type: "numeric"
            , title: "数量"
            , data: "quantity"
            , readOnly: false
            , colWidths: 50
            , editor: CustomEditor
        }

続けてカスタムエディタを作成

let CustomEditor = Handsontable.editors.TextEditor.prototype.extend();
{
    CustomEditor.prototype.beginEditing = function () {        // 編集開始前

        switch (this.prop) {
            case "data_state":    // 状態編集
                {
                    let row = this.row;
                    let dt = <App.TableData>_ht.getSourceDataAtRow(row);   // 直接データ取り出し

                    let dlg = $("#page1_state_popup");
                    let lst = dlg.find("ul.ui-listview");

                    lst.find("li > a").off("click").on("click", function (event: Event) {
                        let cd = parseInt($(this).attr("cd"), 0);
                        let nm = $(this).attr("title");

                        if (isNaN(cd) === false) {
                            dt.data_state_cd = cd;
                            dt.data_state = nm;
                            _ht.render();
                            Popup.close();
                        }
                    });

                    // ポップアップ表示
                    Popup.open(dlg, {
                        positionTo: this.TD
                        , focusSelector: lst
                    });
                }
                break;

            case "data_date":

                break;

            case "data_name":    // 名称編集
                Handsontable.editors.TextEditor.prototype.beginEditing.apply(this, arguments);    // 通常動作
                break;

            case "quantity":    // 数量編集
                {
                    let row = this.row;
                    let dt = <App.TableData>_ht.getSourceDataAtRow(row);   // 直接データ取り出し

                    let dlg = $("#page1_quantity_popup").css("width", "17em");
                    let ipt = dlg.find(".ui-input-text > input").val(dt.quantity);

                    /*
                     * ポップアップボタン押下
                     */
                    dlg.find(".ui-btn").off("click").on("click", function (event: Event) {

                        let cmd = $(this).attr("cmd");
                        switch (cmd) {
                            case "apply":                // OK
                                let v = parseInt(ipt.val(), 0);
                                if (isNaN(v) === false) {
                                    dt.quantity = v;
                                    _ht.render();
                                }
                                Popup.close();
                                break;
                        }
                    });

                    // ポップアップ表示
                    Popup.open(dlg, {
                        positionTo: this.TD
                        , focusSelector: ipt
                        , onOpend: function () {
                            ipt.NumberSpin({ digits: 0, slider: true });
                        }
                    });
                }

                break;

            default:

        }
    };
}

任意名のエディタは適当な組み込みエディタから継承します
編集開始前イベントは作成したCustomEditorから取ることになります
”editor: CustomEditor”としたカラムは編集しようとすると全てこちらに来ます(無論個々にエディタを作成しても構いません)
バインドされたプロパティ名(prop)で分岐させています
beginEditingで何もしないと編集状態にはなりません
”Handsontable.editors.TextEditor.prototype.beginEditing.apply(this, arguments);”なる呪文が必要になります

「状態」(data_state)→Popupでリストを表示
「日付」(data_date)→編集禁止
「名称」(data_name)→デフォルト動作
「数量」(quantity)→Popupで数値入力
としています

HTMLに表示するPopupを追加して完成
/Views/Table/Index.vbhtml

<body class="ui-nodisc-icon ui-alt-icon ui-desktop">
  <div data-role="page" id="page1">

    ....

    <div data-role="popup" data-history="false" id="page1_state_popup" data-arrow="true">
      <ul data-role="listview" data-icon="false">
        <li><a href="#" cd="11" title="State11">状態1</a></li>
        <li><a href="#" cd="22" title="State22">状態2</a></li>
        <li><a href="#" cd="33" title="State33">状態3</a></li>
        <li><a href="#" cd="44" title="State44">状態4</a></li>
        <li><a href="#" cd="55" title="State55">状態5</a></li>
      </ul>
    </div>

    <div data-role="popup" data-history="false" id="page1_quantity_popup" data-arrow="true">
      <div role="main" class="ui-content">
        <form novalidate="novalidate">
          <input type="number" value="" max="10" min="1" step="1">
        </form>
      </div>
      <div data-role="footer">
        <div class="ui-toolbar">
          <div class="ui-right-panel">
            <a href="#" class="ui-btn ui-btn-active" cmd="apply">OK</a>
            <a href="#" class="ui-btn ui-popup-close">キャンセル</a>
          </div>
        </div>
      </div>
    </div>

    ....

  </div>
</body>