ExtJS 4 select multiple CheckColumn checkboxes with checkbox header

ipavlic picture ipavlic · Jul 9, 2012 · Viewed 19.1k times · Source

I have a column of checkcolumn type to enable toggling boolean values. I'd like to be able to toggle all rows for that value at once. Ideally, I'd be able to add a checkbox to the checkcolumn header and listen for changes. Is that possible?

I'd like to note that I am not looking for a checkboxmodel to select rows.

Answer

Reimius picture Reimius · Jul 11, 2012

I have created an updated version of the Ext.ux.CheckColumn for this, just include this code after the extjs code is included:

Ext.define('Ext.ux.CheckColumn', {
    extend: 'Ext.grid.column.Column',
    alias: 'widget.checkcolumn',

    disableColumn: false,
    disableFunction: null,
    disabledColumnDataIndex: null,
    columnHeaderCheckbox: false,

    constructor: function(config) {

        var me = this;
        if(config.columnHeaderCheckbox)
        {
            var store = config.store;
            store.on("datachanged", function(){
                me.updateColumnHeaderCheckbox(me);
            });
            store.on("update", function(){
                me.updateColumnHeaderCheckbox(me);
            });
            config.text = me.getHeaderCheckboxImage(store, config.dataIndex);
        }

        me.addEvents(
            /**
             * @event checkchange
             * Fires when the checked state of a row changes
             * @param {Ext.ux.CheckColumn} this
             * @param {Number} rowIndex The row index
             * @param {Boolean} checked True if the box is checked
             */
            'beforecheckchange',
            /**
             * @event checkchange
             * Fires when the checked state of a row changes
             * @param {Ext.ux.CheckColumn} this
             * @param {Number} rowIndex The row index
             * @param {Boolean} checked True if the box is checked
             */
            'checkchange'
        );

        me.callParent(arguments);
    },

    updateColumnHeaderCheckbox: function(column){
        var image = column.getHeaderCheckboxImage(column.store, column.dataIndex);
        column.setText(image);
    },

    toggleSortState: function(){
        var me = this;
        if(me.columnHeaderCheckbox)
        {
            var store = me.up('tablepanel').store;
            var isAllChecked = me.getStoreIsAllChecked(store, me.dataIndex);
            store.each(function(record){
                record.set(me.dataIndex, !isAllChecked);
                record.commit();
            });
        }
        else
            me.callParent(arguments);
    },

    getStoreIsAllChecked: function(store, dataIndex){
        var allTrue = true;
        store.each(function(record){
            if(!record.get(dataIndex))
                allTrue = false;
        });
        return allTrue;
    },

    getHeaderCheckboxImage: function(store, dataIndex){

        var allTrue = this.getStoreIsAllChecked(store, dataIndex);

        var cssPrefix = Ext.baseCSSPrefix,
            cls = [cssPrefix + 'grid-checkheader'];

        if (allTrue) {
            cls.push(cssPrefix + 'grid-checkheader-checked');
        }
        return '<div class="' + cls.join(' ') + '">&#160;</div>'
    },

    /**
     * @private
     * Process and refire events routed from the GridView's processEvent method.
     */
    processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
        if (type == 'mousedown' || (type == 'keydown' && (e.getKey() == e.ENTER || e.getKey() == e.SPACE))) {
            var record = view.panel.store.getAt(recordIndex),
                dataIndex = this.dataIndex,
                checked = !record.get(dataIndex),
                column = view.panel.columns[cellIndex];
            if(!(column.disableColumn || record.get(column.disabledColumnDataIndex) || (column.disableFunction && column.disableFunction(checked, record))))
            {
                if(this.fireEvent('beforecheckchange', this, recordIndex, checked, record))
                {
                    record.set(dataIndex, checked);
                    this.fireEvent('checkchange', this, recordIndex, checked, record);
                }
            }
            // cancel selection.
            return false;
        } else {
            return this.callParent(arguments);
        }
    },

    // Note: class names are not placed on the prototype bc renderer scope
    // is not in the header.
    renderer : function(value, metaData, record, rowIndex, colIndex, store, view){
        var disabled = "",
            column = view.panel.columns[colIndex];
        if(column.disableColumn || column.disabledColumnDataIndex || (column.disableFunction && column.disableFunction(value, record)))
            disabled = "-disabled";
        var cssPrefix = Ext.baseCSSPrefix,
            cls = [cssPrefix + 'grid-checkheader' + disabled];

        if (value) {
            cls.push(cssPrefix + 'grid-checkheader-checked' + disabled);
        }
        return '<div class="' + cls.join(' ') + '">&#160;</div>';
    }
});

then an example setup of a checkbox column would be like this:

{
    xtype: "checkcolumn",
    columnHeaderCheckbox: true,//this setting is necessary for what you want
    store: (you need to put the grids store here),
    sortable: false,
    hideable: false,
    menuDisabled: true,
    dataIndex: "value_flag",
    listeners: {
        checkchange: function(column, rowIndex, checked){
             //code for whatever on checkchange here
        }
    }
}

Looks like this: enter image description here