初心者のためのExtJS入門

ExtJSを使うので、ついでにまとめていきます

グリッドの機能:編集[classic]

今回はグリッド上での編集機能です。

編集機能はプラグイン(のクラス)で提供されています。グリッド用のプラグインはExt.grid.pluginにあり、編集可能にするにはCellEditing(セル編集)とRowEditing(行編集)を使います。

セル編集

グリッドの1マスずつ編集する場合は、Ext.grid.plugin.CellEditing(http://docs.sencha.com/extjs/6.2.1/classic/Ext.grid.plugin.CellEditing.html)を使います。

/**
 * メモ一覧グリッドクラス。
 *
 * @class Memo.view.list.Grid
 * @extend Ext.grid.Panel
 */
Ext.define('Memo.view.list.Grid', {
    extend: 'Ext.grid.Panel',
    xtype: 'list_grid',

    requires: [
        'Ext.form.field.Text',
        'Ext.grid.column.Date',
        'Ext.grid.plugin.CellEditing'
    ],

    store: 'Memo',

    plugins: [
        {
            ptype: 'cellediting'
        }
    ],

    columns: [
        {
            dataIndex: 'id',
            text: 'ID',
            align: 'right',
            locked: true
        },
        {
            dataIndex: 'title',
            text: 'タイトル',
            width: 250,
            editor: 'textfield',
            renderer: function (value) {
                return Ext.String.htmlEncode(value);
            }
        },
        {
            dataIndex: 'body',
            text: '本文',
            flex: 1,
            renderer: function (value) {
                value = Ext.String.htmlEncode(value);
                return value.replace(/\r?\n/g, '<br/>');
            }
        },
        {
            xtype: 'datecolumn',
            format: 'Y/m/d H:i:s',
            dataIndex: 'created',
            text: '登録日時',
            width: 200
        }
    ],

    listeners: {
        edit: function (editor, e) {
            e.record.save();
        }
    }

});

タイトル列のセルをダブルクリックすると、テキストフィールドが表れて編集できます。

f:id:sham-memo:20170204151358p:plain

まずはプラグインの設定です。↑では、ptypeでエイリアス名を使って設定しています。clicksToEditなどのコンフィグもpluginで指定できます。この時点で画面上での編集操作が有効になります。

次にcolumnsで編集したい列にeditorを設定します。↑では、editor: 'textfield'としており、編集エディタにテキストフィールドを使うようにしています。

最後に保存処理です。編集操作の過程でbeforeedit,canceledit,edit,validateeditイベントが発生するので、編集操作完了時に発生するeditイベントで保存するようにしています。プロキシをローカルストレージにしているので、モデルのsaveメソッドで保存できます。

editorはオブジェクトリテラルにすることもでき、↓のようにすれば入力が必須になります。これだと、確定したときに入力エラーがある場合は、編集がキャンセルされて編集前の値に戻ります。

editor: {
    xtype: 'textfield',
    allowBlank: false
}

↓だと、確定したときに入力エラーがある場合にも編集エディタは閉じません。こっちのほうが多用する気がします。

editor: {
    field: {
        xtype: 'textfield',
        allowBlank: false
    },
    revertInvalid: false
}

1行編集

1行を編集する場合は、Ext.grid.plugin.RowEditing(http://docs.sencha.com/extjs/6.2.1/classic/Ext.grid.plugin.RowEditing.html)を使います。

/**
 * メモ一覧グリッドクラス。
 *
 * @class Memo.view.list.Grid
 * @extend Ext.grid.Panel
 */
Ext.define('Memo.view.list.Grid', {
    extend: 'Ext.grid.Panel',
    xtype: 'list_grid',

    requires: [
        'Ext.form.field.Text',
        'Ext.form.field.TextArea',
        'Ext.grid.column.Date',
        'Ext.grid.plugin.RowEditing'
    ],

    store: 'Memo',

    plugins: [
        {
            ptype: 'rowediting'
        }
    ],

    columns: [
        {
            dataIndex: 'id',
            text: 'ID',
            align: 'right',
            locked: true
        },
        {
            dataIndex: 'title',
            text: 'タイトル',
            width: 250,
            editor: {
                field: {
                    xtype: 'textfield',
                    allowBlank: false
                },
                revertInvalid: false
            },
            renderer: function (value) {
                return Ext.String.htmlEncode(value);
            }
        },
        {
            dataIndex: 'body',
            text: '本文',
            flex: 1,
            editor: 'textarea',
            renderer: function (value) {
                value = Ext.String.htmlEncode(value);
                return value.replace(/\r?\n/g, '<br/>');
            }
        },
        {
            xtype: 'datecolumn',
            format: 'Y/m/d H:i:s',
            dataIndex: 'created',
            text: '登録日時',
            width: 200
        }
    ],

    listeners: {
        edit: function (editor, e) {
            e.record.save();

            this.getView().refresh();
        },
        scope: 'this'
    }
});

f:id:sham-memo:20170204162321p:plain

今度は本文にもeditorを設定しています。テキストエリアで。

保存後にthis.getView().refresh()を実行していますが、テキストエリアで広がった高さが編集完了後にちゃんと調整されなかったので、手動で対応しています(ちなみにExtJS6.2.1です)。こういうのはExtJSで良くある残念なパターンです。。。

Ext.grid.column.Widgetを使って入力フィールドを表示したままにする

頻度は少ないかもしれないですが、こんな感じにもできます。これはプラグイン関係ないです。

/**
 * メモ一覧グリッドクラス。
 *
 * @class Memo.view.list.Grid
 * @extend Ext.grid.Panel
 */
Ext.define('Memo.view.list.Grid', {
    extend: 'Ext.grid.Panel',
    xtype: 'list_grid',

    requires: [
        'Ext.form.field.Text',
        'Ext.form.field.TextArea',
        'Ext.grid.column.Date',
        'Ext.grid.column.Widget'
    ],

    store: 'Memo',

    columns: [
        {
            dataIndex: 'id',
            text: 'ID',
            align: 'right',
            locked: true
        },
        {
            dataIndex: 'title',
            text: 'タイトル',
            width: 250,
            xtype: 'widgetcolumn',
            widget: {
                xtype: 'textfield',
                allowBlank: false,
                listeners: {
                    change: function (field, value) {
                        var record = field.getWidgetRecord();

                        if (record && field.isValid()) {
                            record.set('title', value);
                            record.save();
                        }
                    }
                }
            }
        },
        {
            dataIndex: 'body',
            text: '本文',
            flex: 1,
            xtype: 'widgetcolumn',
            widget: {
                xtype: 'textarea',
                listeners: {
                    change: function (field, value) {
                        var record = field.getWidgetRecord();

                        if (record && field.isValid()) {
                            record.set('body', value);
                            record.save();
                        }
                    }
                }
            }
        },
        {
            xtype: 'datecolumn',
            format: 'Y/m/d H:i:s',
            dataIndex: 'created',
            text: '登録日時',
            width: 200
        }
    ]
});

f:id:sham-memo:20170204170213p:plain

ウィジェットとして、テキストフィールドとテキストエリアを表示させ、changeイベント時に保存しています。ちょっと無理やりな感じもしますが、まあ、こういうことも可能です(今はlistenersプロパティに直接イベントハンドラを設定していますが、きれいに整理するならビューコントローラに書くほうが良さげ)。

メソッドで編集を開始する

CellEditingプラグインの場合、startEditByPositionメソッドで編集を開始できます。そのためには、プラグインの参照を取得する必要があります。(ちなみにRowEditingプラグインの場合は、編集開始するメソッドはstartEditです)

プラグインは、グリッドのgetPluginメソッドで取得できます。その際、引数にプラグインのIDを指定するので、↓のようにIDを振っておきます。

plugins: [
    {
        ptype: 'cellediting',
        id: 'editing'
    }
]

あとはプラグインを取得して、startEditByPositionを実行するだけです。

var grid = this.lookupReference('grid');

var editing = grid.getPlugin('editing');

editing.startEditByPosition({
    row: 3,
    column: 2
});