1. #1
    Sencha User
    Join Date
    Jul 2009
    Posts
    30
    Vote Rating
    7
    da_bar is on a distinguished road

      0  

    Default Ext.ux.CheckCombo

    Ext.ux.CheckCombo


    Combo with multiselection checkboxes.

    Examples: http://extjs.dariofilkovic.com/

    Features:
    - multiselect using checkboxes
    - can be used in a form
    - can configure to use 'all' selector that checks or unchecks all records

    example:

    Ext.create('Ext.ux.CheckCombo',
    {
    addAllSelector: true, //to add all selector to first row
    allText: 'All' //change text for 'all' selector
    });


    css:
    Code:
    /* check combo */ 
    .x-combo-checker { background-position: 50% -2px; margin-left: 1px; background-color: transparent; background-image: url("/extjs/resources/themes/images/default/grid/unchecked.gif"); background-position: -1px -1px; background-repeat: no-repeat; height: 14px; width: 14px; display: inline-block; } 
    .x-boundlist-selected .x-combo-checker { background-image: url("/extjs/resources/themes/images/default/grid/checked.gif"); }
    extension:

    Code:
    Ext.define('Ext.ux.CheckCombo',
    {
        extend: 'Ext.form.field.ComboBox',
        alias: 'widget.checkcombo',
        multiSelect: true,
        allSelector: false,
        noData: false,
        noDataText: 'No combo data',
        addAllSelector: false,
        allSelectorHidden: false,
        enableKeyEvents: true,
        afterExpandCheck: false,
        allText: 'All',
        oldValue: '',
        listeners:
        {
    /* uncomment if you want to reload store on every combo expand
            beforequery: function(qe)
            {
                this.store.removeAll();
                delete qe.combo.lastQuery;
            },
    */
            focus: function(cpt)
            {
                cpt.oldValue = cpt.getValue();
            },
            keydown: function(cpt, e, eOpts)
            {
                var    value = cpt.getRawValue(),
                    oldValue = cpt.oldValue;
                
                if(value != oldValue) cpt.setValue('');
            }
        },
        createPicker: function() 
        {
            var    me = this,
                picker,
                menuCls = Ext.baseCSSPrefix + 'menu',
                opts = Ext.apply(
                {
                    pickerField: me,
                    selModel:
                    {
                        mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
                    },
                    floating: true,
                    hidden: true,
                    ownerCt: me.ownerCt,
                    cls: me.el.up('.' + menuCls) ? menuCls : '',
                    store: me.store,
                    displayField: me.displayField,
                    focusOnToFront: false,
                    pageSize: me.pageSize,
                    tpl: 
                    [
                        '<ul><tpl for=".">',
                            '<li role="option" class="' + Ext.baseCSSPrefix + 'boundlist-item"><span class="x-combo-checker">&nbsp;</span> {' + me.displayField + '}</li>',
                        '</tpl></ul>'
                    ]
                }, me.listConfig, me.defaultListConfig);
    
    
            picker = me.picker = Ext.create('Ext.view.BoundList', opts);
            if(me.pageSize) 
            {
                picker.pagingToolbar.on('beforechange', me.onPageChange, me);
            }        
    
    
            me.mon(picker,
            {
                itemclick: me.onItemClick,
                refresh: me.onListRefresh,
                scope: me
            });
    
    
            me.mon(picker.getSelectionModel(),
            {
                'beforeselect': me.onBeforeSelect,
                'beforedeselect': me.onBeforeDeselect,
                'selectionchange': me.onListSelectionChange,
                scope: me
            });
    
    
            me.store.on('load', function(store)
            {
                if(store.getTotalCount() == 0)
                {
                    me.allSelectorHidden = true;
                    if(me.allSelector != false) me.allSelector.setStyle('display', 'none');
                    if(me.noData != false) me.noData.setStyle('display', 'block');
                }
                else
                {
                    me.allSelectorHidden = false;
                    if(me.allSelector != false) me.allSelector.setStyle('display', 'block');
                    if(me.noData != false) me.noData.setStyle('display', 'none');
                }
            });
    
    
            return picker;
        },
        reset: function()
        {
            var    me = this;
    
    
            me.setValue('');
        },
        setValue: function(value)
        {
            this.value = value;
            if(!value)
            {
                if(this.allSelector != false) this.allSelector.removeCls('x-boundlist-selected');
                return this.callParent(arguments);
            }
    
    
            if(typeof value == 'string') 
            {
                var    me = this,
                    records = [],
                    vals = value.split(',');
    
    
                if(value == '')
                {
                    if(me.allSelector != false) me.allSelector.removeCls('x-boundlist-selected');
                }
                else
                {
                    if(vals.length == me.store.getCount() && vals.length != 0)
                    {
                        if(me.allSelector != false) me.allSelector.addCls('x-boundlist-selected');
                        else me.afterExpandCheck = true;
                    }
                }
    
    
                Ext.each(vals, function(val)
                {
                    var record = me.store.getById(parseInt(val));
                    if(record) records.push(record);
                });
    
    
                return me.setValue(records);
            }
            else return this.callParent(arguments);
        },
        getValue: function()
        {
            if(typeof this.value == 'object') return this.value.join(',');
            else return this.value;
        },
        getSubmitValue: function()
        {
            return this.getValue();
        },
        expand: function()
        {
            var    me = this,
                bodyEl, picker, collapseIf;
    
    
                if(me.rendered && !me.isExpanded && !me.isDestroyed)
                {
                bodyEl = me.bodyEl;
                picker = me.getPicker();
                collapseIf = me.collapseIf;
    
    
                // show the picker and set isExpanded flag
                picker.show();
                me.isExpanded = true;
                me.alignPicker();
                bodyEl.addCls(me.openCls);
    
    
                if(me.noData == false) me.noData = picker.getEl().down('.x-boundlist-list-ct').insertHtml('beforeBegin', '<div class="x-boundlist-item" role="option">'+me.noDataText+'</div>', true);
    
    
                if(me.addAllSelector == true && me.allSelector == false)
                {
                    me.allSelector = picker.getEl().down('.x-boundlist-list-ct').insertHtml('beforeBegin', '<div class="x-boundlist-item" role="option"><span class="x-combo-checker">&nbsp;</span> '+me.allText+'</div>', true);
                    me.allSelector.on('click', function(e)
                    {
                        if(me.allSelector.hasCls('x-boundlist-selected'))
                        {
                            me.allSelector.removeCls('x-boundlist-selected');
                            me.setValue('');
                            me.fireEvent('select', me, []);
                        }
                        else
                        {
                            var records = [];
                            me.store.each(function(record)
                            {
                                records.push(record);
                            });
                            me.allSelector.addCls('x-boundlist-selected');
                            me.select(records);
                            me.fireEvent('select', me, records); 
                        }
                    });
    
    
                    if(me.allSelectorHidden == true) me.allSelector.hide();
                    else me.allSelector.show();
                    
                    if(me.afterExpandCheck == true)
                    {
                        me.allSelector.addCls('x-boundlist-selected');
                        me.afterExpandCheck = false;
                    }
                }
    
    
                // monitor clicking and mousewheel
                me.mon(Ext.getDoc(),
                {
                    mousewheel: collapseIf,
                    mousedown: collapseIf,
                    scope: me
                });
                Ext.EventManager.onWindowResize(me.alignPicker, me);
                me.fireEvent('expand', me);
                me.onExpand();
            }
            else
            {
                me.fireEvent('expand', me);
                me.onExpand();
            }
        },
        alignPicker: function()
        {    
            var me = this,
                picker = me.getPicker();
    
    
            me.callParent();
        
            if(me.addAllSelector == true)
            {
                var height = picker.getHeight();
                height = parseInt(height)+20;
                picker.setHeight(height);
                picker.getEl().setStyle('height', height+'px');
            }
        },
        onListSelectionChange: function(list, selectedRecords)
        {
            var    me = this,
                isMulti = me.multiSelect,
                hasRecords = selectedRecords.length > 0;
            // Only react to selection if it is not called from setValue, and if our list is
            // expanded (ignores changes to the selection model triggered elsewhere)
            if(!me.ignoreSelection && me.isExpanded)
            {
                if(!isMulti)
                {
                    Ext.defer(me.collapse, 1, me);
                }
                /*
                * Only set the value here if we're in multi selection mode or we have
                * a selection. Otherwise setValue will be called with an empty value
                * which will cause the change event to fire twice.
                */
                if(isMulti || hasRecords)
                {
                    me.setValue(selectedRecords, false);
                }
                if(hasRecords)
                {
                    me.fireEvent('select', me, selectedRecords);
                }
                me.inputEl.focus();
    
    
                if(me.addAllSelector == true && me.allSelector != false)
                {
                    if(selectedRecords.length == me.store.getTotalCount()) me.allSelector.addCls('x-boundlist-selected');
                    else me.allSelector.removeCls('x-boundlist-selected'); 
                } 
            }
        }
    });
    Last edited by da_bar; 14 Jan 2013 at 1:58 PM. Reason: Added fixes multiple fixes

  2. #2
    Sencha - Support Team scottmartin's Avatar
    Join Date
    Jul 2010
    Location
    Houston, Tx
    Posts
    8,872
    Vote Rating
    438
    scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future

      0  

    Default


    Thank you for the contribution!

    Regards,
    Scott.

  3. #3
    Ext JS Premium Member
    Join Date
    Apr 2011
    Posts
    5
    Vote Rating
    0
    Edhilion is on a distinguished road

      0  

    Default


    Hi Dario, hi all.

    I just tried to use your checkcombo, and I saw the code on your page was a bit different from the above one.

    Above :
    Code:
    me.allSelector = picker.getEl().createChild('<div class="x-boundlist-item" role="option"><span class="x-combo-checker">&nbsp;</span> '+me.allText+'</div>');
    On the site :
    Code:
    me.allSelector = picker.getEl().insertHtml('afterBegin', '<div class="x-boundlist-item" role="option"><span class="x-combo-checker">&nbsp;</span> '+me.allText+'</div>', true);
    With the above version, the "All" checbox is displayed at the end of the combo list. The site version should be used the have it a the very top.

    And thank you for this component !

  4. #4
    Sencha User
    Join Date
    Jul 2009
    Posts
    30
    Vote Rating
    7
    da_bar is on a distinguished road

      0  

    Default


    Quote Originally Posted by Edhilion View Post
    Hi Dario, hi all.

    I just tried to use your checkcombo, and I saw the code on your page was a bit different from the above one.

    Above :
    Code:
    me.allSelector = picker.getEl().createChild('<div class="x-boundlist-item" role="option"><span class="x-combo-checker">&nbsp;</span> '+me.allText+'</div>');
    On the site :
    Code:
    me.allSelector = picker.getEl().insertHtml('afterBegin', '<div class="x-boundlist-item" role="option"><span class="x-combo-checker">&nbsp;</span> '+me.allText+'</div>', true);
    With the above version, the "All" checbox is displayed at the end of the combo list. The site version should be used the have it a the very top.

    And thank you for this component !
    Yep, fixed it in post. Tnx.

  5. #5
    Sencha User
    Join Date
    Mar 2011
    Location
    Betelgeuse VII
    Posts
    86
    Vote Rating
    3
    fordprefect is on a distinguished road

      0  

    Default


    Thanks - looks great!

  6. #6
    Sencha User
    Join Date
    Aug 2009
    Location
    China
    Posts
    2
    Vote Rating
    0
    zeno is on a distinguished road

      0  

    Default Hi, i get a ui bug

    Hi, i get a ui bug


    when the record is too long, the scrollbar's footer is hide, see the picture,
    Attached Images

  7. #7
    Sencha User
    Join Date
    May 2012
    Posts
    2
    Vote Rating
    0
    vdsabev is on a distinguished road

      0  

    Default Editor in Ext.grid.Panel

    Editor in Ext.grid.Panel


    Has anyone had any luck using the Ext.ux.CheckCombo as an editor in an Ext.grid.Panel? I can't quite grasp the concept of connecting editors to grid cells yet.

  8. #8
    Sencha - Support Team scottmartin's Avatar
    Join Date
    Jul 2010
    Location
    Houston, Tx
    Posts
    8,872
    Vote Rating
    438
    scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future

      0  

    Default


    Have a look at the following:
    http://skirtlesden.com/ux/component-column

    Regards,
    Scott.

  9. #9
    Sencha User
    Join Date
    May 2012
    Posts
    2
    Vote Rating
    0
    vdsabev is on a distinguished road

      0  

    Default


    Hey Scott,
    Thanks for the suggestion! However, we'd like to be able to have thousands of records for the grids we're using. The ComponentColumn is no replacement for an editor in this case, seeing that it renders a separate control for each cell. Or, as the author put it:
    it is intended to be used in small grids where performance is not a problem
    Is there really no simple way to connect a custom widget to the CellEditing plugin? Any widget, not just the CheckCombo. Sorry for being a bit off-topic here.

  10. #10
    Sencha - Support Team scottmartin's Avatar
    Join Date
    Jul 2010
    Location
    Houston, Tx
    Posts
    8,872
    Vote Rating
    438
    scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future

      0  

    Default


    I would not suggest having 'thousands' of records in a grid. You can paginate the grid and you should be fine.

    Scott.