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>'
);
}
darkpriest
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
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.
Powered by vBulletin® Version 4.1.5 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.