PDA

View Full Version : Grouping Combo



Everton Luiz Pascke
22 May 2011, 5:28 PM
Can anyone help me to do a Grouping Combo?
I'm trying but I'm finding many errors.

Thanks!

atian25
22 May 2011, 5:42 PM
u can try to change combo's picker to a grouping grid.

this may be help:
http://www.sencha.com/forum/showthread.php?132328-CLOSED-ComboBox-using-Grid-instead-of-BoundList

Everton Luiz Pascke
28 May 2011, 3:57 PM
@atian25

Thanks for idea, below my solution:

GroupingList


Ext.define('Ext.ux.view.GroupingList', {
extend: 'Ext.view.View',
alias: 'widget.groupinlist',
requires: ['Ext.layout.component.BoundList', 'Ext.toolbar.Paging'],

pageSize: 0,

autoScroll: true,
baseCls: Ext.baseCSSPrefix + 'boundlist',
listItemCls: '',
shadow: false,
trackOver: true,
refreshed: 0,

ariaRole: 'listbox',

componentLayout: 'boundlist',

renderTpl: ['<div class="list-ct"></div>'],

initComponent: function() {
var me = this,
baseCls = me.baseCls,
itemCls = baseCls + '-item';
me.itemCls = itemCls;
me.selectedItemCls = baseCls + '-selected';
me.overItemCls = baseCls + '-item-over';
me.itemSelector = "." + itemCls;

if (me.floating) {
me.addCls(baseCls + '-floating');
}

var tpl = [
'<ul>',
'<tpl for=".">'
];

var padding = 1;

if (Ext.isArray(me.groupField)) {
padding = me.groupField.length;
for (var i = 0; i < me.groupField.length; i++) {
tpl.push(
'<tpl if="xindex == 1 || parent[xindex - 2][\'' + me.groupField[i] + '\'] != values[\'' + me.groupField[i] + '\']">',
'<li class="x-combo-list-group" style="padding-left:' + (i * 16) + 'px;">{[values["' + me.groupField[i] + '"]]}</li>',
'</tpl>'
);
}
}
else {
tpl.push(
'<tpl if="xindex == 1 || parent[xindex - 2][\'' + me.groupField + '\'] != values[\'' + me.groupField + '\']">',
'<li class="x-combo-list-group">{[values["' + me.groupField + '"]]}</li>',
'</tpl>'
);
}
tpl.push(
'<li role="option" class="' + itemCls + '" style="padding-left:' + (padding * 16) + 'px;">{[values["' + me.displayField + '"]]}</li>',
'</tpl>',
'</ul>'
);

me.tpl = Ext.create('Ext.XTemplate', tpl);

if (me.pageSize) {
me.pagingToolbar = me.createPagingToolbar();
}

me.callParent();

Ext.applyIf(me.renderSelectors, {
listEl: '.list-ct'
});
},

createPagingToolbar: function() {
return Ext.widget('pagingtoolbar', {
pageSize: this.pageSize,
store: this.store,
border: false
});
},

onRender: function() {
var me = this,
toolbar = me.pagingToolbar;
me.callParent(arguments);
if (toolbar) {
toolbar.render(me.el);
}
},

bindStore : function(store, initial) {
var me = this,
toolbar = me.pagingToolbar;
me.callParent(arguments);
if (toolbar) {
toolbar.bindStore(store, initial);
}
},

getTargetEl: function() {
return this.listEl || this.el;
},

getInnerTpl: function(displayField) {
return '{' + displayField + '}';
},

refresh: function() {
var me = this;
me.callParent();
if (me.isVisible()) {
me.refreshed++;
me.doComponentLayout();
me.refreshed--;
}
},

initAria: function() {
this.callParent();

var selModel = this.getSelectionModel(),
mode = selModel.getSelectionMode(),
actionEl = this.getActionEl();

if (mode !== 'SINGLE') {
actionEl.dom.setAttribute('aria-multiselectable', true);
}
},

onDestroy: function() {
Ext.destroyMembers(this, 'pagingToolbar', 'listEl');
this.callParent();
}
});

GroupingComboBox


Ext.define('Ext.ux.form.GroupingComboBox', {
extend: 'Ext.form.field.ComboBox',
requires: ['Ext.ux.view.GroupingList'],
alias: ['widget.groupingcombobox', 'widget.groupingcombo'],

initComponent: function() {
var me = this;
if (!me.displayTpl) {
var display = [],
tpl = '<tpl for=".">{0}</tpl>';
if (Ext.isArray(me.groupField)) {
for (var i = 0; i < me.groupField.length; i++) {
display.push('{[values["' + me.groupField[i] + '"]]}');
}
}
else {
display.push('{[values["' + me.groupField + '"]]}');
}
display.push('{[values["' + me.displayField + '"]]}');
me.displayTpl = Ext.String.format(tpl, display.join(this.displaySeparator || ' '));
}
me.callParent();
},

createPicker: function() {
var me = this,
picker,
menuCls = Ext.baseCSSPrefix + 'menu',
opts = Ext.apply({
selModel: {
mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
},
floating: true,
hidden: true,
ownerCt: me.ownerCt,
cls: me.el.up('.' + menuCls) ? menuCls : '',
store: me.store,
groupField: me.groupField,
displayField: me.displayField,
focusOnToFront: false,
pageSize: me.pageSize
}, me.listConfig, me.defaultListConfig);

//picker = me.picker = Ext.create('Ext.view.BoundList', opts);
picker = me.picker = Ext.create('Ext.ux.view.GroupingList', opts);

me.mon(picker, {
itemclick: me.onItemClick,
refresh: me.onListRefresh,
scope: me
});

me.mon(picker.getSelectionModel(), 'selectionchange', me.onListSelectionChange, me);

return picker;
}
});

CSS


.x-combo-list-group {
font : bold 12px tahoma,arial,helvetica,sans-serif;
padding : 2px;
border : 1px solid #fff;
white-space : nowrap;
overflow : hidden;
text-overflow : ellipsis;
}

Example


{
anchor: '100%',
fieldLabel: 'My Grouping ComboBox',
xtype: 'groupingcombobox',
name: 'name',
allowBlank: false,
groupField: ['nivel1', 'nivel2'],// string or array
valueField: 'value',
displayField: 'display',
queryMode: 'local',
typeAhead: true,
store: {
fields: [
{ name: 'value', type: 'int' },
{ name: 'nivel1', type: 'string' },
{ name: 'nivel2', type: 'string' },
{ name: 'display', type: 'string' }
],
sorters: [
{ property: 'nivel1', direction: 'ASC' },
{ property: 'nivel2', direction: 'ASC' },
{ property: 'display', direction: 'ASC' }
],
data: [
{ value: 1, nivel1: 'nivel 1', nivel2: 'nivel 1.1', display: 'display 1' },
{ value: 2, nivel1: 'nivel 1', nivel2: 'nivel 1.1', display: 'display 2' },
{ value: 3, nivel1: 'nivel 1', nivel2: 'nivel 1.1', display: 'display 3' },
{ value: 4, nivel1: 'nivel 2', nivel2: 'nivel 2.1', display: 'display 4' },
{ value: 5, nivel1: 'nivel 2', nivel2: 'nivel 2.1', display: 'display 5' },
{ value: 6, nivel1: 'nivel 2', nivel2: 'nivel 2.1', display: 'display 6' },
{ value: 7, nivel1: 'nivel 3', nivel2: 'nivel 3.1', display: 'display 7' },
{ value: 8, nivel1: 'nivel 3', nivel2: 'nivel 3.1', display: 'display 8' },
{ value: 9, nivel1: 'nivel 3', nivel2: 'nivel 3.1', display: 'display 9' }
]
}
}

mr.amin0
21 Sep 2011, 5:28 AM
Thanks for sharing your extension, i needed a combobox with an 'optgroup' like implementation.
However I found a (minor) bug in the code.

28210

related code (GroupingList):

for (var i = 0; i < me.groupField.length; i++) {
tpl.push(
'<tpl if="xindex == 1 || parent[xindex - 2][\'' + me.groupField[i] + '\'] != values[\'' + me.groupField[i] + '\']">',
'<li class="x-combo-list-group" style="padding-left:' + (i * 16) + 'px;">{[values["' + me.groupField[i] + '"]]}</li>',
'</tpl>'
);
}

As you can see, if the second (or third etc) level group is the same as in the previous item it won't be displayed, however if the parent group is different, it should be.

Here is my solution:


for (var i = 0; i < me.groupField.length; i++) {
var checking = '';
for(var j=i-1;j>=0;j--) {
checking += ' || parent[xindex - 2][\'' + me.groupField[j] + '\'] != values[\'' + me.groupField[j] + '\']';
}
tpl.push(
'<tpl if="xindex == 1 || parent[xindex - 2][\'' + me.groupField[i] + '\'] != values[\'' + me.groupField[i] + '\']'+checking+'">',
'<li class="x-combo-list-group" style="padding-left:' + (i * 16) + 'px;">{[values["' + me.groupField[i] + '"]]}</li>',
'</tpl>'
);
}

Michi_72
28 Feb 2012, 3:48 AM
Hello,

first i want to say thanks for sharing your extension. Very cool feature.

Unfortunately under 4.1.0 Beta 3 this extension is broken.

I show 2 pictures - the first one is with 4.0.7 and the second one with 4.1.0 Beta 3! This is the only difference.

3219732198

I have tried to figure the problem out.

Thanks!

Michi

Michi_72
3 Apr 2012, 6:00 AM
Hello,

has anyone an idea how to solve this?

Any help is useful!

Thanks in advance!

Michi

Solovyevk
27 Nov 2012, 3:29 PM
You can use listConfig.tpl or tpl for simple grouping:


Ext.onReady(function () {


Ext.create('Ext.form.ComboBox', {
fieldLabel: 'Choose City',
store: Ext.create('Ext.data.Store', {
fields: ['country', 'city'],
data: [
{"country": "France", "city": "Paris"},
{"country": "France", "city": "Lion"},
{"country": "France", "city": "Marcel"},
{"country": "Germany", "city": "Berlin"},
{"country": "Germany", "city": "Bonn"},
{"country": "Germany", "city": "Heidelberg"},
{"country": "Russia", "city": "St.Petersburg"},
{"country": "Russia", "city": "Moscow"},
{"country": "Russia", "city": "Novgorod"}
]
}),
queryMode: 'local',
displayField: 'city',
valueField: 'city',
renderTo: Ext.getBody(),
listConfig: {
tpl: Ext.create('Ext.XTemplate',
'<ul><tpl for=".">',
'<tpl if="xindex == 1 || this.getGroupStr(parent[xindex - 2]) != this.getGroupStr(values)">',
'<li class="x-combo-list-group"><b>{[this.getGroupStr(values)]}</b></li>',
'</tpl>',
'<li role="option" class="x-boundlist-item" style="padding-left: 12px">{city}</li>',
'</tpl>' +
'</ul>',
{
getGroupStr: function (values) {
return values.country
}
}
)
}
});
});

peisenmann
14 Mar 2013, 12:09 PM
Based on this StackOverflow answer (http://stackoverflow.com/a/12481276/1449525), I crufted up the following, which seems to work:

42409


Ext.define('common.field.GroupingComboBox', {

extend: 'Ext.form.field.ComboBox',
alias: 'widget.common.field.GroupingComboBox',


constructor: function (args) {
var me = this,
groupField = args.groupField || "group",
groupDisplayField = args.groupDisplayField || groupField,
displayField = args.displayField || "name";


args.tpl = new Ext.XTemplate(
'<tpl for=".">',
'<tpl if="this.' + groupField + ' != values.' + groupField + '">',
'<tpl exec="this.' + groupField + ' = values.' + groupField + '"></tpl>',
'<div class="x-panel-header-default x-panel-header-text-container x-panel-header-text x-panel-header-text-default" title="{' + groupDisplayField + '}">{' + groupDisplayField + '}</div>',
'</tpl>',
'<div class="x-boundlist-item">{' + displayField + '}</div>',
'</tpl>'
);


me.callParent(arguments);
}
});


Then you can use it with a grouping store and you get something like the screenshot.