REQUIRED INFORMATION

Ext version tested:
  • Ext 4.1.0
Browser versions tested against:
  • Any
DOCTYPE tested against:
  • Any
Description:
  • If a CheckColumn with "editable: true" is used within GridPanel, it causes a "mousedown is not defined" JavaScript error when any checkbox is clicked.
  • If a CheckColumn with "editable: true" is used within TreePanel, it causes a "store.getAt is not a function" JavaScript error when any checkbox is clicked.
Steps to reproduce the problem:
  • Run any GridPanel/TreePanel with CheckColumn with "editable: true" and click any checkbox.
The result that was expected:
  • Clicking on a checkbox inverts its state.
The result that occurs instead:
  • A JavaScript occurs.
Test Case:

Apologize, I am in haste. Please see the Steps to reproduce the problem, Debugging, Possible Fix sections.

HELPFUL INFORMATION

Debugging already done:
  • There are three obvious problems with the CheckColumn processEvent function.
1. The problem #1.

This line
Code:
if (mousedown) {
    e.stopEvent();
}
but "mousedown" is not defined as a variable.

I guess it should look
Code:
if (type == 'mousedown') { 
    e.stopEvent();
}
2. The problem #2.

This line
Code:
if (!me.stopSelection)
but "me" is not defined as a variable.

I have add
Code:
me = this
in the "var" section

3. The problem #3.

This line
Code:
record = store.getAt(recordIndex),
It causes a JavaScript error in the case with a TreePanel, because there is no getAt method of its TreeStore.

It might be replaced with
Code:
record = store.getAt ? store.getAt(recordIndex) : view.getRecord(view.getNode(recordIndex)),

Possible fix:
  • Here is the full code of the processEvent function with the suggested fixes.
Ext.ux.CheckColumn processEvent
Code:
Ext.ux.CheckColumn.override({
    processEvent: function (type, view, cell, recordIndex, cellIndex, e) {
        if (this.editable && (type == 'mousedown' || (type == 'keydown' && (e.getKey() == e.ENTER || e.getKey() == e.SPACE)))) {

            var me = this,
                store = view.panel.store,
                record = store.getAt ? store.getAt(recordIndex) : view.getRecord(view.getNode(recordIndex)), //store.getAt(recordIndex),
                dataIndex = this.dataIndex,
                checked = !record.get(dataIndex),
                eventTarget = view.panel.editingPlugin || view.panel;

            var ev = {
                grid: view.panel,
                record: record,
                field: dataIndex,
                value: record.get(this.dataIndex),
                row: view.getNode(recordIndex),
                column: this,
                rowIdx: recordIndex,
                colIdx: cellIndex,
                cancel: false
            };

            if (eventTarget.fireEvent("beforeedit", eventTarget, ev) === false || ev.cancel === true) {
                return;
            }

            ev.originalValue = ev.value;
            ev.value = checked;

            if (eventTarget.fireEvent("validateedit", eventTarget, ev) === false || ev.cancel === true) {
                return;
            }

            if (this.singleSelect) {
                store.suspendEvents();
                store.each(function (record, i) {
                    var value = (i == recordIndex);
                    if (value != record.get(dataIndex)) {
                        record.set(dataIndex, value);
                    }
                });
                store.resumeEvents();
                store.fireEvent("datachanged", store);
            } else {
                record.set(dataIndex, checked);
            }

            this.fireEvent('checkchange', this, recordIndex, record, checked);
            eventTarget.fireEvent('edit', eventTarget, ev);
                    
            if (type == 'mousedown') { //if (mousedown) {
                e.stopEvent();
            }

            // Selection will not proceed after this because of the DOM update caused by the record modification
            // Invoke the SelectionModel unless configured not to do so
            if (!me.stopSelection) {
                view.selModel.selectByPosition({
                    row: recordIndex,
                    column: cellIndex
                });
            }
            // cancel selection.
            return false;
        } else {
            return this.callParent(arguments);
        }
    }
});