PDA

View Full Version : Multiselect 'CheckboxSelect' control



prometheus
20 Apr 2009, 7:21 AM
Hi all, I'm new to ExtJS community, so I hopes that if my control helps someone on multiselect issues.

Usable on:
Select tags - a very visible implementation, user could type one of the available tags, tag added if return pressed, checkbox with tag appears.
Any case where there are so many items available, list seems like unlimited, and we do not want to force the user to "scroll and scroll and select one or some" - this control should be a very useful solution because user colud select items very easily and will alvays see what he/she choosed.
etc.After the PR, code docs have all necessary infos I think.


/**
* Ext.sm.Form.CheckboxSelect - ExtJS Library for sYs-mini SDK
*
* For any licensing informations ask licensing@extjs.com or visit
* http://extjs.com/license
*
* @author Csaba Dobai (prometheus) <csaba.dobai@php-sparcle.com>
* @copyright All rights reserved by author, based on ExtJS 3.0 licensing!
*/

Ext.namespace('Ext.sm.Form');

/**
* @class Ext.sm.Form.CheckboxSelect
* @extends Ext.Panel
* <p><b>Represent a composite control to realize special multiselection.</b></p>
* <p>This control displays an Ext.form.ComboBox, and a panel below the combobox.
* If you select an item from the combobox, a checked checkbox appears within the
* panel. User can uncheck a checkbox, then checkbox disappears (going to remove).</p>
* <p>You can configure fully the ComboBox as usual within the {@link #comboConfig}.
* Checkboxes are displayed in columns, next to each other. On default the control
* has three columns for that, but you can override this by set the {@link #checkboxColumns}
* configuration setting. Checkbox values parsed as array of values. For example you
* have a ComboBox with items ['first'='One', 'second'='Two'] (value=text) and {@link checkboxArrayName}
* has the value 'numbers' - now if you select all items, you have two checkboxes on
* the form, the parsed result is similar: <i>...numbers[]=first&numbers[]=second</i>.</p>
* <p>The code below illustrates how the component works:</p><pre><code>
var win = new Ext.Window({
title : 'Test',
items : [{
xtype : 'form',
autoHeight : true,
items : [{
xtype : 'checkboxselect',
checkboxArrayName : 'numbers',
comboConfig : {
store : [['1', 'One'], ['2', 'Two'], ['3', 'Three'], ['4', 'Four']],
fieldLabel : 'Test'
}
}],
buttons: [{
text: 'Save',
handler: function()
{
var fp = this.findParentByType('form');

if(fp.getForm().isValid()){
Ext.Msg.alert('Submitted Values', 'The following will be sent to the server: <br />'+
fp.getForm().getValues(true));
}
}
}]
}]
});

win.show();</code></pre></p>
*/
Ext.sm.Form.CheckboxSelect = Ext.extend(Ext.Panel, {
// private
comboConfigDefault : {
typeAhead : true,
forceSelection : true,
triggerAction : "all",
selectOnFocus :true
},

// private
cbpanelConfigDefault : {
xtype : "panel",
border : false,
fieldLabel : 'no-label',
labelStyle : 'visibility:hidden;',
labelSeparator : '',
layout : 'column',
},

// private
cbpanelColConfig : {
defaultType : 'checkbox',
layout : 'form',
border : false,
defaults : {
hideLabel : true,
anchor : '100%'
},
},

// private
combo : null,

// private
checkboxPanel : null,

/**
* @cfg {Object} comboConfig
* This is the config of component`s ComboBox, here you can set the fieldLabel and
* store etc on it. Default settings are: typeAhead=true, forceSelection=true.
*/
comboConfig : {},

/**
* @cfg {String} checkboxArrayName Name of Ext.form.Checkbox components. A
* default 'unnamed' set, but you must change this if you want a normal result
* on the server-side.
*/
checkboxArrayName : 'unnamed',

/**
* @cfg {Integer} checkboxColumns
* Number of columns in checkbox display panel. Default is 3.
*/
checkboxColumns : 3,
/**
* @cfg {String/Object} layout
* Layout is fixed to 'form', because this panel is going to a FormPanel
* component now.
*/

// private
lastColIdx : 0,

// private
initComponent : function()
{
var comboConfig = (this.comboConfig == undefined ? {} : this.comboConfig);
var colCfg;
var columns = [];

Ext.sm.Form.CheckboxSelect.superclass.initComponent.call(this);
this.layout = 'form';

// combo
comboConfig = Ext.applyIf(comboConfig, this.comboConfigDefault);
this.combo = new Ext.form.ComboBox(comboConfig);

// checkbox panel
for (var i=0; i<this.checkboxColumns; i++)
{
colCfg = Ext.apply({}, this.cbpanelColConfig);
columns.push(colCfg);
}
Ext.apply(this.cbpanelConfigDefault, {
layoutConfig : {columns : this.checkboxColumns},
items : columns
});
this.checkboxPanel = new Ext.Panel(this.cbpanelConfigDefault);

// listener
this.combo.on('select', function(self, record, index){this.onComboSelect(self, record, index)}.createDelegate(this));

// add to me
this.add(this.combo);
this.add(this.checkboxPanel);
},

// private
onComboSelect : function(self, record, index)
{
var cb;
var p;

if (this.checkboxPanel.find('value', record.data.value).length == 0)
{
p = this.getColumnNext();
cb = new Ext.form.Checkbox({
boxLabel : record.data.text,
name : this.checkboxArrayName + '[]',
inputValue : record.data.value,
checked : true
});
cb.on('check', function(self, checked){this.onCheckboxCheck(self, checked)}.createDelegate(this));
p.add(cb);
p.bubble(function(){this.render(); return true;});
}

return true;
},

// private
onCheckboxCheck : function(self, checked)
{
if (!checked)
{
this.removeCheckbox(self);
}
},

/**
* Removes the passed checkbox from the panel and reorders the other.
* @param {Component} cb The checkbox to remove.
*/
removeCheckbox : function(cb)
{
var cbColList = [];
var cbConfigList = [];
var p;
var i, j = 0;
var maxLength = 0;
var cbi;

// Clone all checkbox components in order, except the removed one.
for (var i=0; i<this.checkboxColumns; i++)
{
cbColList.push(this.checkboxPanel.get(i).findByType('checkbox'));
}
for (var i=0; i<cbColList.length; i++)
{
if (maxLength < cbColList[i].length) maxLength = cbColList[i].length;
}
for (var i=0; i<maxLength; i++)
{
for (var j=0; j<this.checkboxColumns; j++)
{
cbi = this.checkboxPanel.get(j).get(i);
if (cbi !== undefined && cbi.getId() != cb.getId())
{
cbConfigList.push(cbi.cloneConfig());
}
}
}

// Remove checkboxes from all columns.
for (var i=0; i<this.checkboxColumns; i++)
{
this.checkboxPanel.get(i).removeAll();
}

// recreate all checkboxes
this.lastColIdx = 0;
for (var i=0; i<cbConfigList.length; i++)
{
p = this.getColumnNext();
cbConfigList[i].on('check', function(self, checked){this.onCheckboxCheck(self, checked)}.createDelegate(this));
p.add(cbConfigList[i]);
p.bubble(function(){this.render(); return true;});
}

},

// private
getColumnNext : function()
{
var key = this.lastColIdx;

this.lastColIdx++;
if (this.lastColIdx >= this.checkboxColumns) this.lastColIdx = 0;

return this.checkboxPanel.get(key);
},

/**
* Returns selected items` values in array.
* @return {Array}
*/
getSelectedValues : function()
{
var result = [];
var chs;

chs = this.checkboxPanel.findByType('checkbox');
for (var i=0; i<chs.length; i++)
{
result.push(chs[i].inputValue);
}

return result;
}
});

Ext.reg('checkboxselect', Ext.sm.Form.CheckboxSelect);

prometheus
24 Apr 2009, 5:24 AM
Little fixes:

Deleted a comma, IE may not eat that.
Added getSelectedValues() method.Any replies would be nice :)

only_do@126.com
3 May 2009, 5:33 PM
it is not working..

prometheus
6 May 2009, 12:15 PM
it is not working..
Hi, I read that sadly :(. Please inform me about your Ext version, browser and browser version, and give me a little more info about the context of using.

Thanks for response!

prometheus
8 May 2009, 2:47 PM
Ok, now I posted a brand new version of this control, it has many bugfixes and new improvments.

More on this post: CLICK ME I must see that! (http://extjs.com/forum/showthread.php?p=327494#post327494)

This thread is not updated in the future! All of my support for this component is in the topic linked above!

Regards,