PDA

View Full Version : Grid Header Filters



d.zucconi
14 Oct 2011, 7:52 AM
This is the ExtJS 4 version of ExtJS 3.x plugin Ext.ux.grid.GridHeaderFilters available on thread
http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters
(http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters)The plugin has been rewritten to be compatible with the new ExtJS version and now works directly on new Ext.data.Store filters, using Ext.util.Filter objects.
This is only a preview release for now, tested on FF,Chrome and IE9 with local and remote stores.
Some functions will be improved in future versions.

Source code
Preview release - 14/10/11
16/10/11 - Fixed resizeFilterContainer method (thanks to bsot)
17/10/11 - Modified beforeheaderfiltersapply event handler result management (thanks to bsot)
18/10/11 - Fixed wrong variable name in setFieldValue method code

Version 0.1.0 - 04/11/11
Modified events parameters adding the number of active (not empty) filters
Added adjustFilterWidth on grid afterlayout event (thanks to zaggi)

Version 0.2.0 - 05/03/12
Changed plugin class name (Ext.ux.grid.plugin.HeaderFilters)
Filters are rendered on headerCt afterrender event (thanks to puja for the hint)
Modified adjustFilterWidth checking if containers are ready (thanks to Jad)
Filter values are parsed only if the corresponding field isValid
Adjusted filters tooltip
Configurable status property for stateful filter values



/**
* Plugin that enable filters on the grid header.<br>
* The header filters are integrated with new Ext4 <code>Ext.data.Store</code> filters.<br>
* It enables:
* <ul>
* <li>Instances of <code>Ext.form.field.Field</code> subclasses that can be used as filter fields into column header</li>
* <li>New grid methods to control header filters (get values, update, apply)</li>
* <li>New grid events to intercept plugin and filters events</li>
* </ul>
*
* The plugins also enables the stateful feature for header filters so filter values are stored with grid status if grid is stateful.<br>
*
* # Enable filters on grid columns
* The plugin checks the <code>filter</code> attribute that can be included into each column configuration.
* The value of this attribute can be a <code>Ext.form.field.Field</code> configuration or an array of field configurations to enable more
* than one filter on a single column.<br>
* Field <code>readOnly</code> and <code>disabled</code> attributes are managed by the plugin to avoid filter update or filter apply.
* The filter field configuration also supports some special attributes to control filter configuration:
* <ul>
* <li>
* <code>filterName</code>: the name of the filter that will be used when the filter is applied to store filters (as <code>property</code> of <code>Ext.util.Filter</code> attribute).
* If this attribute is not specified the column <code>dataIndex</code> will be used. <b>NOTE</b>: The filter name must be unique in a grid header. The plugin doesn't support correctly filters
* with same name.
* </li>
* </ul>
* On the grid configuration the {@link #headerFilters} attribute is supported. The value must be an object with name-values pairs for filters to initialize.
* It can be used to initialize header filters in grid configuration.
*
* # Plugin configuration
* The plugin supports also some configuration attributes that can be specified when the plugin is created (with <code>Ext.create</code>).
* These parameters are:
* <ul>
* <li>{@link #stateful}: Enables filters save and load when grid status is managed by <code>Ext.state.Manager</code>. If the grid is not stateful this parameter has no effects</li>
* <li>{@link #reloadOnChange}: Intercepts the special {@link #headerfilterchange} plugin-enabled grid event and automatically reload or refresh grid Store. Default true</li>
* <li>{@link #ensureFilteredVisible}: If one filter on column is active, the plugin ensures that this column is not hidden (if can be made visible).</li>
* <li>{@link #enableTooltip}: Enable active filters description tootip on grid header</li>
* </ul>
*
* # Enabled grid methods
* <ul>
* <li><code>setHeaderFilter(name, value, reset)</code>: Set a single filter value</li>
* <li><code>setHeaderFilters(filters, reset)</code>: Set header filters</li>
* <li><code>getHeaderFilters()</code>: Set header filters</li>
* <li><code>getHeaderFilterField(filterName)</code>: To access filter field</li>
* <li><code>resetHeaderFilters()</code>: Resets filter fields calling reset() method of each one</li>
* <li><code>clearHeaderFilters()</code>: Clears filter fields</li>
* <li><code>applyHeaderFilters()</code>: Applies filters values to Grid Store. The store will be also refreshed or reloaded if {@link #reloadOnChange} is true</li>
* </ul>
*
* # Enabled grid events
* <ul>
* <li>{@link #headerfilterchange} : fired by Grid when some header filter changes value</li>
* <li>{@link #headerfiltersrender} : fired by Grid when header filters are rendered</li>
* <li>{@link #beforeheaderfiltersapply} : fired before filters are applied to Grid Store</li>
* <li>{@link #headerfiltersapply} : fired after filters are applied to Grid Store</li>
* </ul>
*
* @author Damiano Zucconi - http://www.isipc.it
* @version 0.2.0
*/
Ext.define('Ext.ux.grid.plugin.HeaderFilters',{

ptype: 'gridheaderfilters',

alternateClassName: ['Ext.ux.grid.HeaderFilters', 'Ext.ux.grid.header.Filters'],

requires: [
'Ext.container.Container',
'Ext.tip.ToolTip'
],




grid: null,

fields: null,

containers: null,

storeLoaded: false,

filterFieldCls: 'x-gridheaderfilters-filter-field',

filterContainerCls: 'x-gridheaderfilters-filter-container',

filterRoot: 'data',

tooltipTpl: '{[Ext.isEmpty(values.filters) ? this.text.noFilter : "<b>"+this.text.activeFilters+"</b>"]}<br><tpl for="filters"><tpl if="value != \'\'">{[values.label ? values.label : values.property]} = {value}<br></tpl></tpl>',

lastApplyFilters: null,

bundle: {
activeFilters: 'Active filters',
noFilter: 'No filter'
},

/**
* @cfg {Boolean} stateful
* Specifies if headerFilters values are saved into grid status when filters changes.
* This configuration can be overridden from grid configuration parameter <code>statefulHeaderFilters</code> (if defined).
* Used only if grid <b>is stateful</b>. Default = true.
*
*/
stateful: true,

/**
* @cfg {Boolean} reloadOnChange
* Specifies if the grid store will be auto-reloaded when filters change. The store
* will be reloaded only if is was already loaded. If the store is local or it doesn't has remote filters
* the store will be always updated on filters change.
*
*/
reloadOnChange: true,

/**
* @cfg {Boolean} ensureFilteredVisible
* If the column on wich the filter is set is hidden and can be made visible, the
* plugin makes the column visible.
*/
ensureFilteredVisible: true,

/**
* @cfg {Boolean} enableTooltip
* If a tooltip with active filters description must be enabled on the grid header
*/
enableTooltip: true,

statusProperty: 'headerFilters',

rendered: false,

constructor: function(cfg)
{
if(cfg)
{
Ext.apply(this,cfg);
}
},

init: function(grid)
{
this.grid = grid;

/*var storeProxy = this.grid.getStore().getProxy();
if(storeProxy && storeProxy.getReader())
{
var reader = storeProxy.getReader();
this.filterRoot = reader.root ? reader.root : undefined;
}*/
/**
* @cfg {Object} headerFilters
* <b>Configuration attribute for grid</b>
* Allows to initialize header filters values from grid configuration.
* This object must have filter names as keys and filter values as values.
* If this plugin has {@link #stateful} enabled, the saved filters have priority and override these filters.
* Use {@link #ignoreSavedHeaderFilters} to ignore current status and apply these filters directly.
*/
if(!grid.headerFilters)
grid.headerFilters = {};


if(Ext.isBoolean(grid.statefulHeaderFilters))
{
this.setStateful(grid.statefulHeaderFilters);
}

this.grid.addEvents(
/**
* @event headerfilterchange
* <b>Event enabled on the Grid</b>: fired when at least one filter is updated after apply.
* @param {Ext.grid.Panel} grid The grid
* @param {Ext.util.MixedCollection} filters The applied filters (after apply). Ext.util.Filter objects.
* @param {Ext.util.MixedCollection} prevFilters The old applied filters (before apply). Ext.util.Filter objects.
* @param {Number} active Number of active filters (not empty)
* @param {Ext.data.Store} store Current grid store
*/
'headerfilterchange',
/**
* @event headerfiltersrender
* <b>Event enabled on the Grid</b>: fired when filters are rendered
* @param {Ext.grid.Panel} grid The grid
* @param {Object} fields The filter fields rendered. The object has for keys the filters names and for value Ext.form.field.Field objects.
* @param {Object} filters Current header filters. The object has for keys the filters names and for value the filters values.
*/
'headerfiltersrender',
/**
* @event beforeheaderfiltersapply
* <b>Event enabled on the Grid</b>: fired before filters are confirmed. If the handler returns false no filter apply occurs.
* @param {Ext.grid.Panel} grid The grid
* @param {Object} filters Current header filters. The object has for keys the filters names and for value the filters values.
* @param {Ext.data.Store} store Current grid store
*/
'beforeheaderfiltersapply',
/**
* @event headerfiltersapply
*<b>Event enabled on the Grid</b>: fired when filters are confirmed.
* @param {Ext.grid.Panel} grid The grid
* @param {Object} filters Current header filters. The object has for keys the filters names and for value the filters values.
* @param {Number} active Number of active filters (not empty)
* @param {Ext.data.Store} store Current grid store
*/
'headerfiltersapply'
);

this.grid.on({
scope: this,
columnresize: this.resizeFilterContainer,
beforedestroy: this.onDestroy,
beforestatesave: this.saveFilters,
afterlayout: this.adjustFilterWidth
});

this.grid.headerCt.on({
scope: this,
afterrender: this.renderFilters
});

this.grid.getStore().on({
scope: this,
load: this.onStoreLoad
});

if(this.reloadOnChange)
{
this.grid.on('headerfilterchange',this.reloadStore, this);
}

if(this.stateful)
{
this.grid.addStateEvents('headerfilterchange');
}

//Enable new grid methods
Ext.apply(this.grid,
{
headerFilterPlugin: this,
setHeaderFilter: function(sName, sValue)
{
if(!this.headerFilterPlugin)
return;
var fd = {};
fd[sName] = sValue;
this.headerFilterPlugin.setFilters(fd);
},
/**
* Returns a collection of filters corresponding to enabled header filters.
* If a filter field is disabled, the filter is not included.
* <b>This method is enabled on Grid</b>.
* @method
* @return {Array[Ext.util.Filter]} An array of Ext.util.Filter
*/
getHeaderFilters: function()
{
if(!this.headerFilterPlugin)
return null;
return this.headerFilterPlugin.getFilters();
},
/**
* Set header filter values
* <b>Method enabled on Grid</b>
* @method
* @param {Object or Array[Object]} filters An object with key/value pairs or an array of Ext.util.Filter objects (or corresponding configuration).
* Only filters that matches with header filters names will be set
*/
setHeaderFilters: function(obj)
{
if(!this.headerFilterPlugin)
return;
this.headerFilterPlugin.setFilters(obj);
},
getHeaderFilterField: function(fn)
{
if(!this.headerFilterPlugin)
return;
if(this.headerFilterPlugin.fields[fn])
return this.headerFilterPlugin.fields[fn];
else
return null;
},
resetHeaderFilters: function()
{
if(!this.headerFilterPlugin)
return;
this.headerFilterPlugin.resetFilters();
},
clearHeaderFilters: function()
{
if(!this.headerFilterPlugin)
return;
this.headerFilterPlugin.clearFilters();
},
applyHeaderFilters: function()
{
if(!this.headerFilterPlugin)
return;
this.headerFilterPlugin.applyFilters();
}
});
},



saveFilters: function(grid, status)
{
status[this.statusProperty] = (this.stateful && this.rendered) ? this.parseFilters() : grid[this.statusProperty];
},

setFieldValue: function(field, value)
{
var column = field.column;
if(!Ext.isEmpty(value))
{
field.setValue(value);
if(!Ext.isEmpty(value) && column.hideable && !column.isVisible() && !field.isDisabled() && this.ensureFilteredVisible)
{
column.setVisible(true);
}
}
else
{
field.setValue('');
}
},

renderFilters: function()
{
this.destroyFilters();

this.fields = {};
this.containers = {};




var filters = this.grid.headerFilters;

/**
* @cfg {Boolean} ignoreSavedHeaderFilters
* <b>Configuration parameter for grid</b>
* Allows to ignore saved filter status when {@link #stateful} is enabled.
* This can be useful to use {@link #headerFilters} configuration directly and ignore status.
* The state will still be saved if {@link #stateful} is enabled.
*/
if(this.stateful && this.grid[this.statusProperty] && !this.grid.ignoreSavedHeaderFilters)
{
Ext.apply(filters, this.grid[this.statusProperty]);
}

var storeFilters = this.parseStoreFilters();
filters = Ext.apply(storeFilters, filters);

var columns = this.grid.headerCt.getGridColumns(true);
for(var c=0; c < columns.length; c++)
{
var column = columns[c];
if(column.filter)
{
var filterContainerConfig = {
itemId: column.id + '-filtersContainer',
cls: this.filterContainerCls,
layout: 'anchor',
bodyStyle: {'background-color': 'transparent'},
border: false,
width: column.getWidth(),
listeners: {
scope: this,
element: 'el',
mousedown: function(e)
{
e.stopPropagation();
},
click: function(e)
{
e.stopPropagation();
},
keydown: function(e){
e.stopPropagation();
},
keypress: function(e){
e.stopPropagation();
if(e.getKey() == Ext.EventObject.ENTER)
{
this.onFilterContainerEnter();
}
},
keyup: function(e){
e.stopPropagation();
}
},
items: []
}

var fca = [].concat(column.filter);

for(var ci = 0; ci < fca.length; ci++)
{
var fc = fca[ci];
Ext.applyIf(fc, {
filterName: column.dataIndex,
fieldLabel: column.text || column.header,
hideLabel: fca.length == 1
});
var initValue = Ext.isEmpty(filters[fc.filterName]) ? null : filters[fc.filterName];
Ext.apply(fc, {
cls: this.filterFieldCls,
itemId: fc.filterName,
anchor: '-1'
});
var filterField = Ext.ComponentManager.create(fc);
filterField.column = column;
this.setFieldValue(filterField, initValue);
this.fields[filterField.filterName] = filterField;
filterContainerConfig.items.push(filterField);
}

var filterContainer = Ext.create('Ext.container.Container', filterContainerConfig);
filterContainer.render(column.el);
this.containers[column.id] = filterContainer;
column.setPadding = Ext.Function.createInterceptor(column.setPadding, function(h){return false});
}
}

if(this.enableTooltip)
{
this.tooltipTpl = new Ext.XTemplate(this.tooltipTpl,{text: this.bundle});
this.tooltip = Ext.create('Ext.tip.ToolTip',{
target: this.grid.headerCt.el,
//delegate: '.'+this.filterContainerCls,
renderTo: Ext.getBody(),
html: this.tooltipTpl.apply({filters: []})
});
this.grid.on('headerfilterchange',function(grid, filters)
{
var sf = filters.filterBy(function(filt){
return !Ext.isEmpty(filt.value);
});
this.tooltip.update(this.tooltipTpl.apply({filters: sf.getRange()}));
},this);
}

this.applyFilters();
this.rendered = true;
this.grid.fireEvent('headerfiltersrender',this.grid,this.fields,this.parseFilters());
},

onStoreLoad: function()
{
this.storeLoaded = true;
},

onFilterContainerEnter: function()
{
this.applyFilters();
},

resizeFilterContainer: function(headerCt,column,w,opts)
{
if(!this.containers) return;
var cnt = this.containers[column.id];
if(cnt)
{
cnt.setWidth(w);
cnt.doLayout();
}
},

destroyFilters: function()
{
this.rendered = false;
if(this.fields)
{
for(var f in this.fields)
Ext.destroy(this.fields[f]);
delete this.fields;
}

if(this.containers)
{
for(var c in this.containers)
Ext.destroy(this.containers[c]);
delete this.containers;
}
},

onDestroy: function()
{
this.destroyFilters();
Ext.destroy(this.tooltip, this.tooltipTpl);
},

adjustFilterWidth: function()
{
if(!this.containers) return;
var columns = this.grid.headerCt.getGridColumns(true);
for(var c=0; c < columns.length; c++)
{
var column = columns[c];
if (column.filter && column.flex)
{
this.containers[column.id].setWidth(column.getWidth()-1);
}
}
},

resetFilters: function()
{
if(!this.fields)
return;
for(var fn in this.fields)
{
var f = this.fields[fn];
if(!f.isDisabled() && !f.readOnly && Ext.isFunction(f.reset))
f.reset();
}
this.applyFilters();
},

clearFilters: function()
{
if(!this.fields)
return;
for(var fn in this.fields)
{
var f = this.fields[fn];
if(!f.isDisabled() && !f.readOnly)
f.setValue('');
}
this.applyFilters();
},

setFilters: function(filters)
{
if(!filters)
return;

if(Ext.isArray(filters))
{
var conv = {};
Ext.each(filters, function(filter){
if(filter.property)
{
conv[filter.property] = filter.value;
}
});
filters = conv;
}
else if(!Ext.isObject(filters))
{
return;
}




this.initFilterFields(filters);
this.applyFilters();
},

getFilters: function()
{
var filters = this.parseFilters();
var res = new Ext.util.MixedCollection();
for(var fn in filters)
{
var value = filters[fn];
var field = this.fields[fn];
res.add(new Ext.util.Filter({
property: fn,
value: value,
root: this.filterRoot,
label: field.fieldLabel
}));
}
return res;
},

parseFilters: function()
{
var filters = {};
if(!this.fields)
return filters;
for(var fn in this.fields)
{
var field = this.fields[fn];
if(!field.isDisabled() && field.isValid())
filters[field.filterName] = field.getSubmitValue();
}
return filters;
},

initFilterFields: function(filters)
{
if(!this.fields)
return;




for(var fn in filters)
{
var value = filters[fn];
var field = this.fields[fn];
if(field)
{
this.setFieldValue(filterField, initValue);
}
}
},

countActiveFilters: function()
{
var fv = this.parseFilters();
var af = 0;
for(var fn in fv)
{
if(!Ext.isEmpty(fv[fn]))
af ++;
}
return af;
},

parseStoreFilters: function()
{
var sf = this.grid.getStore().filters;
var res = {};
sf.each(function(filter){
var name = filter.property;
var value = filter.value;
if(name && value)
{
res[name] = value;
}
});
return res;
},

applyFilters: function()
{
var filters = this.parseFilters();
if(this.grid.fireEvent('beforeheaderfiltersapply', this.grid, filters, this.grid.getStore()) !== false)
{
var storeFilters = this.grid.getStore().filters;
var exFilters = storeFilters.clone();
var change = false;
var active = 0;
for(var fn in filters)
{
var value = filters[fn];

var sf = storeFilters.findBy(function(filter){
return filter.property == fn;
});

if(Ext.isEmpty(value))
{
if(sf)
{
storeFilters.remove(sf);
change = true;
}
}
else
{
var field = this.fields[fn];
if(!sf || sf.value != filters[fn])
{
var newSf = new Ext.util.Filter({
root: this.filterRoot,
property: fn,
value: filters[fn],
label: field.fieldLabel
});
if(sf)
{
storeFilters.remove(sf);
}
storeFilters.add(newSf);
change = true;
}
active ++;
}
}

this.grid.fireEvent('headerfiltersapply', this.grid, filters, active, this.grid.getStore());
if(change)
{
var curFilters = this.getFilters();
this.grid.fireEvent('headerfilterchange', this.grid, curFilters, this.lastApplyFilters, active, this.grid.getStore());
this.lastApplyFilters = curFilters;
}
}
},

reloadStore: function()
{
var gs = this.grid.getStore();
if(this.grid.getStore().remoteFilter)
{
if(this.storeLoaded)
{
gs.currentPage = 1;
gs.load();
}
}
else
{
if(gs.filters.getCount())
{
if(!gs.snapshot)
gs.snapshot = gs.data.clone();
else
{
gs.currentPage = 1;
}
gs.data = gs.snapshot.filter(gs.filters.getRange());
var doLocalSort = gs.sortOnFilter && !gs.remoteSort;
if(doLocalSort)
{
gs.sort();
}
// fire datachanged event if it hasn't already been fired by doSort
if (!doLocalSort || gs.sorters.length < 1)
{
gs.fireEvent('datachanged', gs);
}
}
else
{
if(gs.snapshot)
{
gs.currentPage = 1;
gs.data = gs.snapshot.clone();
delete gs.snapshot;
gs.fireEvent('datachanged', gs);
}
}
}
}
});

asani
15 Oct 2011, 4:44 AM
I have problem with this plugin, all time have error in gridplugin.js:453


Uncaught TypeError: Cannot read property 'gridcolumn-1051' of null

bsot
15 Oct 2011, 7:10 AM
I had the same problem. You can add a check before using this.containers in resizeFilterContainer :



resizeFilterContainer: function (headerCt, column, w, opts) {
if (!this.containers)
return;
var cnt = this.containers[column.id];
if (cnt) {
cnt.setWidth(w);
cnt.doLayout();
}
},

d.zucconi
16 Oct 2011, 7:26 AM
I had the same problem. You can add a check before using this.containers in resizeFilterContainer :



resizeFilterContainer: function (headerCt, column, w, opts) {
if (!this.containers)
return;
var cnt = this.containers[column.id];
if (cnt) {
cnt.setWidth(w);
cnt.doLayout();
}
},

Thanks. Code updated on first post of this thread.

Arjuna75
17 Oct 2011, 11:54 PM
Very good plugin!

Thank you :)

krish.sadasivam
26 Oct 2011, 7:02 AM
Thanks a lot d.zucconi.. =D>

zaggi
28 Oct 2011, 1:11 AM
When you set column with flex property, filter input after render has default width (100).

My proposal is:

add function to grid afterlayout event


afterlayout: this.adjustFilterWidth



adjustFilterWidth: function() {
var columns = this.grid.headerCt.getGridColumns(true);
for(var c=0; c < columns.length; c++) {
var column = columns[c];
if (column.filter && column.flex) {
this.containers[column.id].setWidth(column.getWidth()-1);
}
}
}


This is effective solution. Width -1 <- is nicer ;)

Spenna
3 Nov 2011, 4:24 AM
Can't get this to work, could you provide a working sample?

d.zucconi
4 Nov 2011, 1:42 AM
When you set column with flex property, filter input after render has default width (100).

My proposal is:

add function to grid afterlayout event


afterlayout: this.adjustFilterWidth
...

Thanks for your suggestion, code updated on the first post of this thread.

swisssphere
4 Nov 2011, 6:53 AM
Bongiorno d.zucconi

Grazie per la tua lavora. Thank you for your work. I'm a newcomer working with extjs.

I made some tries with a grid using an infinite-slider function for reloading data from a MySql-table with many records.
I used the examle "infinite-scroll" and added your class and other stuff. I use external sort and filter.
A lot is working fine. You can see it on http://holzundsonne.ch/extdemo1.

The Problem now is: If you set the filter at the addresscoloumn to "94", you get 450 records back. The first 200 where loaded and 20 of them are displayed correct. But size of the "scrollbuttom" insn't resized to 450 records, it has still the size for the unfiltered 9000 records. Second, when I scroll down, there are multiple times the rownumbers between 1 to 450.

Do you have a hint, how I can fix that?
Many thanks and Saluti Cordiale


Programmcode: 29030


29.11.2011:
Hello d.zucconi
I still have this problem with the resize of the scrollbutton and displaying multiple time the data-records at the grid. Here is an example, see http://holzundsonne.ch/extdemo1:

- no filter applied: result 8995 record, scrollbarbutton is small, scrolling is OK
- filter for column address=19: result 423 records, scrollbarbutton isn't resized, scrolling is not correct
- filter for column address=197: result 27 records, scrollbarbutton isn't resized, scrolling is not correct
- filter for column address=1970: result 9 records, no scrollbar is nessesary, OK

Please help me, how I can refresh the size of scrollbarbutton correct.
Best regards and many thanks.

30.11.2011 I've founded a solution:
The "infinite-scroll" example uses a property called
invalidateScrollerOnRefresh: falsethis disabled the resizing of the scrollbar. My solution is now to allow the resizing of the scrollbar in "applyFilters":

...
this.grid.fireEvent('headerfiltersapply', this.grid, filters, active, this.grid.getStore());
if(change)
{
var curFilters = this.getFilters();
this.grid.fireEvent('headerfilterchange', this.grid, curFilters, this.lastApplyFilters, active, this.grid.getStore());
this.lastApplyFilters = curFilters;
this.grid.invalidateScrollerOnRefresh= true;
}
...

Greetings

Leila
20 Nov 2011, 10:30 AM
Great plugin! Thanks a lot.

vn_vinod
21 Dec 2011, 9:46 PM
Hi,

When I add Grouped Header to the first column the filter is not displayed. Implemented filter to http://dev.sencha.com/deploy/ext-4.0.2a/examples/grid/group-header-grid.html

Posted the same issue at http://www.sencha.com/forum/showthread.php?163799-Grouped-Header-First-Column-Filter-Not-Displayed&p=696201#post696201

My Code



Ext.onReady(function() {
Ext.QuickTips.init();

// sample static data for the store
var myData = [
['3m Co', 71.72, 0.02, 0.03, '9/1 12:00am'],
['Alcoa Inc', 29.01, 0.42, 1.47, '9/1 12:00am'],
['Altria Group Inc', 83.81, 0.28, 0.34, '9/1 12:00am'],
['American Express Company', 52.55, 0.01, 0.02, '9/1 12:00am'],
['American International Group, Inc.', 64.13, 0.31, 0.49, '9/1 12:00am'],
['AT&T Inc.', 31.61, -0.48, -1.54, '9/1 12:00am'],
['Boeing Co.', 75.43, 0.53, 0.71, '9/1 12:00am'],
['Caterpillar Inc.', 67.27, 0.92, 1.39, '9/1 12:00am'],
['Citigroup, Inc.', 49.37, 0.02, 0.04, '9/1 12:00am'],
['E.I. du Pont de Nemours and Company', 40.48, 0.51, 1.28, '9/1 12:00am'],
['Exxon Mobil Corp', 68.1, -0.43, -0.64, '9/1 12:00am'],
['General Electric Company', 34.14, -0.08, -0.23, '9/1 12:00am'],
['General Motors Corporation', 30.27, 1.09, 3.74, '9/1 12:00am'],
['Hewlett-Packard Co.', 36.53, -0.03, -0.08, '9/1 12:00am'],
['Honeywell Intl Inc', 38.77, 0.05, 0.13, '9/1 12:00am'],
['Intel Corporation', 19.88, 0.31, 1.58, '9/1 12:00am'],
['International Business Machines', 81.41, 0.44, 0.54, '9/1 12:00am'],
['Johnson & Johnson', 64.72, 0.06, 0.09, '9/1 12:00am'],
['JP Morgan & Chase & Co', 45.73, 0.07, 0.15, '9/1 12:00am'],
['McDonald\'s Corporation', 36.76, 0.86, 2.40, '9/1 12:00am'],
['Merck & Co., Inc.', 40.96, 0.41, 1.01, '9/1 12:00am'],
['Microsoft Corporation', 25.84, 0.14, 0.54, '9/1 12:00am'],
['Pfizer Inc', 27.96, 0.4, 1.45, '9/1 12:00am'],
['The Coca-Cola Company', 45.07, 0.26, 0.58, '9/1 12:00am'],
['The Home Depot, Inc.', 34.64, 0.35, 1.02, '9/1 12:00am'],
['The Procter & Gamble Company', 61.91, 0.01, 0.02, '9/1 12:00am'],
['United Technologies Corporation', 63.26, 0.55, 0.88, '9/1 12:00am'],
['Verizon Communications', 35.57, 0.39, 1.11, '9/1 12:00am'],
['Wal-Mart Stores, Inc.', 45.45, 0.73, 1.63, '9/1 12:00am']
];

/**
* Custom function used for column renderer
* @param {Object} val
*/
function change(val) {
if (val > 0) {
return '<span style="color:green;">' + val + '</span>';
} else if (val < 0) {
return '<span style="color:red;">' + val + '</span>';
}
return val;
}

/**
* Custom function used for column renderer
* @param {Object} val
*/
function pctChange(val) {
if (val > 0) {
return '<span style="color:green;">' + val + '%</span>';
} else if (val < 0) {
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}

// create the data store
var store = Ext.create('Ext.data.ArrayStore', {
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
],
data: myData
});

// create the Grid
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columnLines: true,
columns: [{
text: 'Company',
columns: [{
text : 'Company',
flex : 1,
sortable : false,
dataIndex: 'company',
filter: {
xtype: 'textfield'
}
}]
}, {
text: 'Stock Price',
columns: [{
text : 'Price',
width : 75,
sortable : true,
renderer : 'usMoney',
dataIndex: 'price',
filter: {
xtype: 'textfield'
}
}, {
text : 'Change',
width : 75,
sortable : true,
renderer : change,
dataIndex: 'change'
}, {
text : '% Change',
width : 75,
sortable : true,
renderer : pctChange,
dataIndex: 'pctChange'
}]
}, {
text : 'Last Updated',
width : 85,
sortable : true,
renderer : Ext.util.Format.dateRenderer('m/d/Y'),
dataIndex: 'lastChange'
}],
height: 350,
width: 600,
title: 'Grouped Header Grid',
renderTo: 'grid-example',
viewConfig: {
stripeRows: true
},
plugins: [Ext.create('Ext.ux.grid.GridHeaderFilters')]
});
});


Thank you in advance.

marco.napetti
16 Jan 2012, 1:43 AM
Hi,
I'm trying to use your plugin, my grid needs to often change its columns, but when I call
this.reconfigure(null, aColumns); this exception gets throwed:
this.containers[column.id] is undefined
GridHeaderFilters.js Line 489

Maybe this plugin is incompatible with reconfigure?
The only way I can get it working is putting it on the first columns definitions, the problems starts after reconfigure.


Thank you in advance.
Marco

puya
1 Feb 2012, 6:12 AM
Congratulations, great plugin!

There was an issue when having a grid in a hidden panel. The grid was rendered (rendered = true, afterender was called), but the actual columns were not rendered yet so renderFilters failed. the solution was to not listen to grid's after render, but to headerCt's after render, like so :



this.grid.on({
scope: this,
columnresize: this.resizeFilterContainer,
beforedestroy: this.onDestroy,
beforestatesave: this.saveFilters,
afterlayout: this.adjustFilterWidth
});
this.grid.headerCt.on({
scope: this,
afterrender: function(){
this.renderFilters();
}
});

Jad
17 Feb 2012, 7:10 AM
Hello, very great plugin :-)

But I have found a bug

When you try to create a grid having this plugin like this


var panel = Ext.create('grid', { region: 'center' });
this.centerArea.add(panel);
this.centerArea.layout.setActiveItem(panel);


I have fixed it



adjustFilterWidth: function()
{
if(!this.containers) return;
var columns = this.grid.headerCt.getGridColumns(true);
for(var c=0; c < columns.length; c++)
{
var column = columns[c];
if (column.filter && column.flex)
{
this.containers[column.id].setWidth(column.getWidth()-1);
}
}
},

KakaxiTaDie
4 Mar 2012, 8:48 AM
Hi!I'm using EXTJS 4.0 .Your plugin is great! Now I need a dynamic grid (json configuired) with filters on the header .With it I can get the store and columnModel from the database.But the plugin doesn't work because the filters disappear.Can't it re-configure the columnModel after grid initialization? Can you help me?Thanks!

d.zucconi
4 Mar 2012, 11:09 PM
Can't it re-configure the columnModel after grid initialization ?
Grid re-configuration is not currently supported.

Thanks to puya and Jad for their fixes and suggestions. I'm going to update the source code on the first page ASAP.

qamarjtahir
7 Mar 2012, 6:38 AM
In my case the filter renders well but throws a db error while trying to filter on any column.

The error for example that I get is: missing right parenthesis

Does any body get this type of error or any db error.

Shouldn't the plugin handle the filtering of data?

JIMECKELS
7 Mar 2012, 9:37 AM
Filtering on date fields do not respect the dateFormat of the filter definition.


filter: { xtype: 'datefield', dateFormat: 'Y-m-d H:i:s' }


I've made a change locally on my system so that the format provided is respected, so the filter that gets passed back to the server (on remote filters) look as I expect. Is this the way you'd expect date filtering to take place?


parseFilters: function()
{
var filters = {};
var filterValue;
if(!this.fields)
return filters;
for(var fn in this.fields)
{
var field = this.fields[fn];
if(!field.isDisabled())
{
filterValue = field.getValue();
if (field.dateFormat && Ext.isDate(filterValue))
{
filters[field.filterName] = Ext.Date.format(filterValue,field.dateFormat);
}
else
{
filters[field.filterName] = filterValue;
}
}
}
return filters;
},



Also, on more general note, why is the filter that is created on the store differently formatted (when inspecting the params on the server-side call) than the filter that the Ext.ux.grid.FiltersFeature uses?

Ext.ux.grid.FiltersFeature params looks something like ...


filter[{"type":"date","comparison":"eq","value":"1999-01-01 00:00:00","field":"SUNRISE_DATE"}]


Ext.ux.grid.GridHeaderFilters params looks something like ...


filter[{"property":"SUNRISE_DATE","value":"1999-01-01T00:00:00"}]


With this "fix" in place, my params for date ftilering look consistent as the provided dateFormat suggests.



filter[{"property":"SUNRISE_DATE","value":"1999-01-01 00:00:00"}]


If I am doing this incorrectly, or my expectations of the dateFormat handing is incorrect, any guidance would be appreciated.

Thanks.

mik83only
25 Mar 2012, 11:25 PM
Is there a way to use server-side filtering with this plugin ?

UPDATE: I figured out it can be done with store's remoteFilter parameter

eriscae
5 Apr 2012, 12:56 AM
About datefield format in the filter, instead of:


filter: { xtype: 'datefield', dateFormat: 'Y-m-d H:i:s' }
try:


filter: { xtype: 'datefield', format: 'Y-m-d H:i:s' }

It works for me

ExtJS 3.3.0
Firefox 3.6.28

Eugent
12 Apr 2012, 4:56 AM
Hello, i have a question about plugin work with checkbox fields. How i can configure this plugins for correct operation with checkbox? Event "change" does not corect.

oliver.schulze
13 Apr 2012, 3:52 PM
Hello,

first: great plugin, very useful.

It works great with ExtJS 4.07, but I tried it with ExtJS 4.1 RC3, and there it doesn't work, there are two issues, I could not figure out how to fix it:

1. Filtering is not working
2. When Plugin is in a list within a tab panel an the panel is switched, then an error occurs. ExtJS tries to call something on ownerLayout for the headers additional containers, containing the filters' input fields... but the ownerLayout-Variable is not set.

I need ExtJS 4.1 for some other issues, that where fixed (like radiogroup-handling, ...), so it would be great if the Grid Header Filters Plugin would also work there

Thank you for helping!

Eugent
17 Apr 2012, 6:13 AM
Hello, in use this plugin i have a column:

{
header: 'Дата',
xtype: 'datecolumn',
format: 'd.m.Y',
dataIndex: 'DATE',
filter: {
xtype: 'datefield',
format: 'd.m.Y'
}
},

but when store is filtered it is no show results with input date. Can you help me?

Rajagopla.bekkam
20 Apr 2012, 6:33 AM
Great Pluggin!

But I have below problem , I am able to create combo in the filter header. but filter combo are empty. because I dont want to define filter values in combo like this
'store : [['a','type1'],['b','type2']]

I want these values load from gridstore that particular colummn,

{header: "DAYS TO DEADLINE", width: 80, dataIndex: 'DAYS TO DEADLINE', sortable: true, filter: {xtype:"combo",'store : [['a','type1'],['b','type2']]
,mode:'local', filterName:"DAYS TO DEADLINE"}},


Please suggest how to load these filter combo values from ..store:Gridstore..whic was defined for loading data into grid...

mik83only
3 May 2012, 10:19 PM
It works great with ExtJS 4.07, but I tried it with ExtJS 4.1 RC3, and there it doesn't work, there are two issues, I could not figure out how to fix it:

Thank you for helping!

I confirm, plugin doesn't work with 4.1

d.zucconi
3 May 2012, 11:47 PM
Hello,

first: great plugin, very useful.

It works great with ExtJS 4.07, but I tried it with ExtJS 4.1 RC3, and there it doesn't work, there are two issues, I could not figure out how to fix it:

1. Filtering is not working

I've tested the plugin with ExtJS 4.1.0 and simple remote JSON store linked to my grids for now and it seems to work properly.
Trying to use local store, filters are applied but grid data is not refreshed. This could be caused by the missing refresh event that is not fired on filter apply. If you have a problem with local store, try to add the following lines into the reloadStore method:


{
gs.sort();
}
else
{
gs.fireEvent('datachanged', gs);
gs.fireEvent('refresh', gs);
}
}
else
{
if(gs.snapshot)
{
gs.currentPage = 1;
gs.data = gs.snapshot.clone();
delete gs.snapshot;
gs.fireEvent('datachanged', gs);
gs.fireEvent('refresh', gs);
}
}

Rajagopla.bekkam
4 May 2012, 2:26 PM
Thanks d.Zucconi,

Ext js 4 grid header pluggin works great when I add this pluggin in my grid.

I have found few problems with filter combo(as I made them as Combo).

Filtering is not working with exact match. means. I have following example with column Values

[[['1'],['type1'],[['12',['type2']],[['3'],['type3']]]..

when I select ' type1'. in filter combo. I suppose to get only [[['1'],['type1']

but I am getting '[[['1'],['type1'][['12',['type2']]. Basically, It is not doing exact match in the store.

How Can I apply the filter for multiple values?. I knew it is available and works for ext js 3 or lower versions right now it is working only for one value of Filter

Filtering is not applying till hit 'Enter' in keyboard. how can i make this so that filtering should be applied as soon select some value from filter combo. ?

Can somebody give some suggestions?

finkelscott
7 May 2012, 3:09 PM
I need to create a row below the grid header to contain the column filters (for the purpose of styling the filters differently from the column headers). Any hints on how do this?

Of course the column filters must move if the header is moved...

http://www.sencha.com/forum/attachment.php?attachmentid=34971&d=1336426486

Thanks in advance.

ps: I should note that today the Filters work (via Ext.ux.grid.GridHeaderFilters) but are bundled together with the column headers. What I need is a separate row for the filters as depicted above.

Rajagopla.bekkam
8 May 2012, 6:10 AM
Hi

How to configure more than one filter on same column for this pluggin in ext js 4 grid ..?

Can some body suggest on this?

Pigor
30 May 2012, 1:44 PM
Hello,

I want to filter the buffered records. I know that it isn't possible with extjs4 but is it possible with this plugin?

Thank you

karaozgur
10 Jun 2012, 11:21 PM
Hi,

Thanks for plugin.

If grid has locked column, header filter does not works.
Here is my fix for it:


renderFilters: function () {
...
var columns = this.grid.view.getGridColumns(); //var columns = this.grid.headerCt.getGridColumns(true);
...
adjustFilterWidth: function () {
...
var columns = this.grid.view.getGridColumns(); //this.grid.headerCt.getGridColumns(true);
...

mrhomer
12 Jun 2012, 12:51 AM
I get an error in line 553 filterField' is undefined in the HeaderFilters.js. That is when i use the function setHeaderFilter

Fix please

Thanks

mcouillard
13 Jun 2012, 8:06 AM
Here's a fix to manually setting column filters, like when setting default filters on page load.



initFilterFields: function(filters)
{
if(!this.fields)
return;

for(var fn in filters)
{
var value = filters[fn];
var field = this.fields[fn];
if(field)
{
//this.setFieldValue(filterField, initValue); //wrong!
this.setFieldValue(field,value); //fixed!
}
}
},

qwikso
14 Jun 2012, 3:27 AM
Hi d.zucconi,
I'm using this plugin more than two years and I'm absolutely satisfied. Now we are thinking about migrating to ExtJS 4.x but I've already found out, that there is any support for grid reconfiguration - this is unfortunately a very important functionality in our application and it's now a 'blocker' for us:(

Please, which priority has this feature in your TODO list resp. when can we expect it?

Thanks a lot.
Best regards
qwikso

prijithkr
27 Jun 2012, 9:10 PM
Object Expected Error

Happy to know that they have a GridHeader Plugin for EXT 4.1 too
But i am still facing problem in including it to the code, i tried implementing it in a basic code, still i get an exception

I think i am missing something in including the plug in....

This is my app.js file




Ext.Loader.setConfig({enabled:true});
JPMC = Ext.create("Ext.app.Application",{
name: 'JPMC',
appFolder: 'app',
launch: function() {

Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['name', 'email', 'phone'],
data:{'items':[
{ 'name': 'Lisa', "email":"lisa@simpsons.com", "phone":"555-111-1224" },
{ 'name': 'Bart', "email":"bart@simpsons.com", "phone":"555-222-1234" },
{ 'name': 'Homer', "email":"home@simpsons.com", "phone":"555-222-1244" },
{ 'name': 'Marge', "email":"marge@simpsons.com", "phone":"555-222-1254" }
]},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}
});
Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: Ext.data.StoreManager.lookup('simpsonsStore'),
plugins: [new Ext.ux.grid.GridHeaderFilters()],
columns: [
{ header: 'Name', dataIndex: 'name', filter: {xtype:"textfield", filterName:"Name"} },
{ header: 'Email', dataIndex: 'email', flex: 1,filter: {xtype:"textfield", filterName:"Email"} },
{ header: 'Phone', dataIndex: 'phone', filter: {xtype:"textfield", filterName:"Phone"} }
],
height: 200,
width: 400,
renderTo: Ext.getBody()
});
}

});





I have also copy pasted the GridHeaderFilter.js inside the src/ux/grid folder and included it in my HTML file too




<html>
<head>
<title>JPMC Compliance</title>
<link rel="stylesheet" type="text/css" href="extjs-4.1/resources/css/ext-all.css">
<link rel="stylesheet" type="text/css" href="resources/css/compliance.css">

<script type="text/javascript" src="extjs-4.1/ext-all.js"></script>
<script type="text/javascript" src="extjs-4.1/src/ux/grid/GridHeaderFilters.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript">
Ext.Loader.setPath({
'Ext.ux': 'extjs-4.1/src/ux/'
});
Ext.require([

'Ext.ux.grid.GridHeaderFilters',
'Ext.grid.*'

]);
</script>



</head>
<body>
</body>
</html>



But still i get an Object expected error, Am I missing something in including the plug in or am I doing anything extra? Please help me, I am very new to EXTJS,

Jad
28 Jun 2012, 11:31 PM
Hello
I have a column like this


{
header: 'Creation Date',
dataIndex: 'creationDate',
renderer: function(value) { return value ? Ext.Date.format(new Date(value), Ext.Date.patterns.ShortDate) : ''; },
flex: 1,
field: 'textfield',
format: Ext.Date.patterns.ShortDate,
filter: [
Ext.create('Ext.form.field.Date', {
filterName:"CDFrom",
format: Ext.Date.patterns.ShortDate,
hideLabel :true,
listeners: {
change: function(field, newValue, oldValue) {
headerFilterPlugin.applyFilters();
},
buffer: 200
}
}),
Ext.create('Ext.form.field.Date', {
filterName:"CDTo",
format: Ext.Date.patterns.ShortDate,
hideLabel :true,
listeners: {
change: function(field, newValue, oldValue) {
headerFilterPlugin.applyFilters();
},
buffer: 200
}
})
]
}


How can i have this 2 fields in the same line with width 50%

Thanks for help

Jad
29 Jun 2012, 5:19 AM
maybe very bad a solution :



me.addListener('headerfiltersrender', function (grid, filters) {
var resize = function (component) {
component.anchor = '50%';
component.doComponentLayout();
};


resize(filters.CDFrom);
resize(filters.CDTo);


}, me);

pierluigi
2 Jul 2012, 3:27 AM
Sorry, my question is very simple:
How to install this plugin? Where I put the file?

Thanks

Jad
2 Jul 2012, 3:39 AM
Hello you can install the file like this

yourAppFolder/Ext/ux/grid/GridHeaderFilters.js

pierluigi
2 Jul 2012, 3:44 AM
Thanks

Have I to add this Ext.Loader.setPath('Ext.ux', 'ux'); ?
Maybe some "requires" directive?

pierluigi
2 Jul 2012, 3:53 AM
I've tried to install this plugin, and I get this error

c is not a constructor



chrome://firebug/content/blank.gif

....instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+'...





Any suggest?

crocop21
2 Jul 2012, 1:12 PM
For this example i need the code php for behind? somebody it has?

Eugent
15 Jul 2012, 9:01 AM
Helo, i use it in my project.

With ExtJS 4.1 it not work on filter store without reload. Do you have any idea?

Jad
3 Aug 2012, 6:37 AM
Hello,

Any update for 4.1 ?

siddmuk2005
6 Sep 2012, 1:55 AM
Great Plugin works well. Thanks for great post. It works for me on ext 4.1.1 RC2.

allanon7
11 Sep 2012, 8:30 AM
It`s problem with datachanged event:
- find gs.fireEvent('datachanged', gs); and replace on gs.fireEvent('refresh', gs);
It`s wowrk for me.

mikih
13 Sep 2012, 5:25 AM
Hi folks,

first of all thanks a lot for all the efforts! :) Now to my question? Are there any example out there? Google find nothing...

I've been using a filter object in the columns items:

filter: {
xtype: 'textfield'
}

which works will but combobox doesnt get filled... is it possible to make a date range picker?

It would be just nice if it would render the standard filter from the dropdown right under the header.


Thanks in advance!

l3chris
26 Oct 2012, 11:40 AM
How do I implement/incorporate this and make it work?

Thanks

l3chris
26 Oct 2012, 12:49 PM
So I got the plugin "working" in that the column headers have text fields and hovering over them indicates what "filters are active" when I type something in. However, they don't actually change what's being displayed in the grid, all the results are still there regardless of what I type. What's wrong?

gayathr
15 Nov 2012, 5:23 AM
I applied this plug in .Every thing is workingfine except filter for "date field". I coded as follows
{xtype: 'datecolumn', text: "Note Date", dataIndex: 'NoteDate', align: 'center', sortable: true, filter:{
xtype:'datefield',emptyText : 'Filter for',format: 'Y-m-d', allowBlank: true},
renderer: Ext.util.Format.dateRenderer('Y-m-d')
}

Can u please suggest what needs to do for " date filter " functioanlity

ClaudeG
15 Nov 2012, 2:59 PM
I'm reading your code and you have a few references to CSS such as x-gridheaderfilters-filter-field. Can you paste the CSS somewhere? because it doesn't seem to be in ExtJS itself, at least, not that I can find.

gayathr
16 Nov 2012, 1:26 AM
Hi

I am using HedaerFilters plugin to get row inside the grid. I need Datepicker in yyyymmdd format . Can you please let me know how to get that one

gayathr
16 Nov 2012, 3:05 AM
filter: { xtype: 'datefield', format: 'Y-m-d'} is not filtering data for ext js 4.1 version. Please suggest what needs tp do

gayathr
19 Nov 2012, 3:01 AM
Please let me know whether this supports yyyy-mm-dd format for the date picker calender for date field. Also let me know remote filtering will supports or not

prijithkr
11 Dec 2012, 11:20 PM
I think its a bug,

If my code has columns which are given width, instead of Flex, as i need Horizondal scroll bar to appear, also there is header filter assigned to each columns,

While Choosing a hidden column from "Select Column", the filters are not render properly,

but once i stretch the column, it gets rendered properly..

But than i tried changing the code grid filter plugin, since it handles only column.flex, previosuly, I tried adding a condition for column.width too and it worked fine



adjustFilterWidth: function() {
if(!this.containers) return;
var columns = this.grid.headerCt.getGridColumns(true);
for(var c=0; c < columns.length; c++)
{
var column = columns[c];
if (column.filter && column.flex)
{
this.containers[column.id].setWidth(column.getWidth()-1);
}
else if (column.filter && column.width)
{
this.containers[column.id].setWidth(column.getWidth()-1);
}
}
}

likdike
24 Dec 2012, 1:52 AM
i add dynamically columns in grid, follows:


var column = Ext.create('Ext.grid.column.Column', {text: 'New Column'});gridView.headerCt.insert(gridView.columns.length, column);gridView.getView().refresh();

How dinamically add filters to headers column's, such code not work



var column = Ext.create('Ext.grid.column.Column', {text: 'New Column', filter: {xtype: 'textfield'}});gridView.headerCt.insert(gridView.columns.length, column);gridView.getView().refresh();

carlov
17 Jan 2013, 9:18 AM
Hi

i am trying to use the plugin to implement a multiselect combo header filter



filter: {xtype: 'combo', multiSelect : true, store: ...}



but i get 'TypeError: gs.data is undefined' on line 711

gs.snapshot = gs.data.clone();

Any idea?
Thanks!

carlov
17 Jan 2013, 9:36 AM
i fixed it by adding
remoteFilter: true to the grid store ...

eternasparta
5 Feb 2013, 1:30 AM
How do I implement/incorporate this and make it work?

Thanks

Add in your grid class the following rows:


- plugin for the grid:


plugins: [Ext.create('Ext.ux.grid.plugin.HeaderFilters')/*, ... other plugins here */]


- column configuration:


columns:[{ /*other configurations for your column:*/
header: 'Accepted', dataIndex: 'accepted', flex: 1,
/*filter plugin configuration:*/
filterable: true, filter:{xtype: 'textfield' /* i've used a simple textbox*/}}
/*, other columns here */]

tdikarim
5 Feb 2013, 6:15 AM
Hi,

Great plugin. Thanks for sharing.

I want to apply a cls for the input field contained in the header. How to apply it ?

Thanks

jheid
12 Feb 2013, 7:37 AM
For supporting combo boxes I added


if (filterField.xtype == 'combo')
filterField.on ('change', this.onFilterContainerEnter, this);

at the end of

dotti
14 Mar 2013, 6:43 AM
Hi,

is there a Verion for ExtJS 4.2.0

mfg

Klaus

qooleot
21 Mar 2013, 3:12 PM
It works in 4.2 after I changed this in two places:

var columns = this.grid.headerCt.getGridColumns(true);

to this:

var columns = this.grid.headerCt.getGridColumns();

I'll need to go figure out what the 'true' was for and test with nested headers and other things though...but a few basic filters on a basic grid works.

mikegk
4 Apr 2013, 1:08 AM
Applied now your fix - and it works like a dream! :))

linyajun
10 Jul 2013, 9:36 PM
great plugin!
but it have some problem in ie with extjs4.2.
when grid columns text is all English or chinese it used perfect.
some problem show when columns have english and chinese text,then english
column does not show filter.like44834
Ext.define('Ext.ux.grid.plugin.HeaderFilters', {
extend : 'Ext.AbstractPlugin',
mixins : {
observable : 'Ext.util.Observable'
},
containers : {},
stateful : false,
booleanSotre : {
fields : [ 'name', 'value' ],
data : [ {
"name" : "--",
"value" : ""
}, {
"name" : "true",
"value" : "true"
}, {
"name" : "false",
"value" : "false"
} ]
},
init : function(grid) {
this.fields = [];
this.grid = grid;
this.grid.filterContainers= {};
this.grid.filterFields = [];
if(grid.lockable === true){
this.columns = Ext.Array.union(this.grid.normalGrid.columns,this.grid.lockedGrid.columns);
this.grid.normalGrid.headerCt.on({scope : this,afterrender : this.renderFilters});
}
else{
this.columns = this.grid.columns;
this.grid.headerCt.on({scope : this,afterrender : this.renderFilters});
}
this.grid.on({
scope : this,
columnresize : this.resizeFilterContainer,
afterlayout : this.adjustFilterWidth
});

},
renderFilters : function() {
var me = this;
Ext.each(me.columns, function(column, index) {
if(column.filter === false) return;
var filter;
if(Ext.isObject(column.filter))
filter = column.filter;
else
filter = {};
var config = {
value: filter.value
};
if (column.xtype == 'xdatecolumn') {
config.xtype = 'changedatefield';
config.format = column.format;
if(column.dataType == 'time'){
config.datextype = 'xtimefield';
config.validator = me.timeValidator;
}
if (column.dataType == 'date') {
config.datextype = 'Ext.picker.Date';
config.validator = me.dateValidator;
} else {
config.datextype = 'Ext.ux.DateTimePicker';
config.validator = me.dateTimeValidator;
}
} else if (column.xtype == 'booleancolumn') {
config.xtype = 'combo';
config.store = Ext.create('Ext.data.Store', me.booleanSotre);
config.displayField = 'name';
config.valueField = 'value';
config.forceSelection = true;
} else if (column.xtype == 'numbercolumn') {
if (column.dataType == 'int')
config.validator = me.intNumberValidator;
else if (column.dataType == 'byte')
config.validator = me.byteNumberValidator;
else if (column.dataType == 'short')
config.validator = me.shortNumberValidator;
else if (column.dataType == 'long')
config.validator = me.longNumberValidator;
}
var filterContainerConfig = {
itemId : column.id + '-filtersContainer',
cls : this.filterContainerCls,
layout : 'fit',
border : false,
width : column.width,
listeners : {
scope : this,
element : 'el',
mousedown : function(e) {e.stopPropagation();},
click : function(e) {e.stopPropagation();},
keydown : function(e) {e.stopPropagation();},
keypress : function(e) {
e.stopPropagation();
if (e.getKey() == Ext.EventObject.ENTER) {
var flag = true;
Ext.Array.each(me.fields, function(field) {
if (!field.isValid()) {
flag = false;
return false;
}
});
if (flag === true)
me.onFilterContainerEnter();
}
},
keyup : function(e) {e.stopPropagation();}
},
items : []
};
var field = Ext.ComponentManager.create(Ext.apply({
xtype : 'textfield',
filterName : column.dataIndex,
cls : this.filterFieldCls,
itemId : column.id + '-filter',
anchor : '-1'
}, config));
var filterContainer = Ext.create('Ext.container.Container', filterContainerConfig);
filterContainer.items.add(field);

filterContainer.render(column.el);//i think filter does not render in ie7|ie8|ie9
me.fields.push(field);
column.itemCon = filterContainer;
me.containers[column.id] = filterContainer;
column.setPadding = Ext.Function.createInterceptor(
column.setPadding, function(h) {
return false;
});
});
},

onFilterContainerEnter : function() {
var me = this;
var filters = [];
me.grid.store.clearFilter(true);
Ext.Array.each(me.fields, function(field) {
if (field.getValue()) {
var values = {};
values['property'] = field.filterName;
values['value'] = field.getValue();
filters.push(values);
me.grid.store.filters.add(values);
}
});
this.grid.store.loadPage(1);
},

resizeFilterContainer : function(headerCt, column, w, opts) {
if (!this.containers)
return;
var cnt = this.containers[column.id];
if (cnt) {
cnt.setWidth(w);
cnt.doLayout();
}
},

adjustFilterWidth : function() {
if (!this.containers)
return;
var columns = this.columns;
for ( var c = 0; c < columns.length; c++) {
var column = columns[c];
if (column.filter && column.flex) {
this.containers[column.id].setWidth(column.getWidth() - 1);
}
}
},
byteNumberValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var pos = value.indexOf(".");
if (pos == -1) {
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.isNumeric(words[j]);
if (bln === true && words[j] <= 127 && words[j] >= -128) {
count++;
} else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
} else
return Eap.errors.inputError;
},

shortNumberValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var pos = value.indexOf(".");
if (pos == -1) {
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.isNumeric(words[j]);
if (bln === true && words[j] <= 32767 && words[j] >= -32768) {
count++;
} else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
} else
return Eap.errors.inputError;
},
intNumberValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var pos = value.indexOf(".");
if (pos == -1) {
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.isNumeric(words[j]);
if (bln === true && words[j] <= 2147483647&& words[j] >= -2147483648) {
count++;
} else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
} else
return Eap.errors.inputError;
},
longNumberValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var pos = value.indexOf(".");
if (pos == -1) {
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.isNumeric(words[j]);
if (bln === true && words[j] <= 9223372036854775807 && words[j] >= -9223372036854775808) {
count++;
} else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
} else
return Eap.errors.inputError;
},

dateValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.Date.parse(words[j], Eap.dateFormat);
if (bln != null)
count++;
else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
},

timeValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.Date.parse(words[j], Eap.timeFormat);
if (bln != null)
count++;
else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
},
dateTimeValidator : function(value) {
if (value == null || value === "")
return true;
if (value == '--')
return true;
if (value == '!!')
return true;
var items = value.split(/\s*,\s*/);
for ( var i = 0; i < items.length; i++) {
var words = items[i].split(/\s*~\s*/);
var count = 0;
for ( var j = 0; j < words.length; j++) {
var bln = Ext.Date.parse(words[j], Eap.datetimeFormat);
if (bln != null)
count++;
else if (Ext.Date.parse(words[j], Eap.dateFormat) != null)
count++;
else if (words[j] === "")
continue;
else {
return Eap.errors.inputError;
}
}
if (count < 1)
return Eap.errors.inputError;
}
return true;
}
});
/* vim:ts=4:sw=4:et:ai
*/

ng_varun
31 Aug 2013, 2:07 PM
Please share usage of Ext.ux.grid.plugin.HeaderFilters for local filtering option.

mcouillard
16 Sep 2013, 11:20 AM
So far so good using ExtJS 4.2.2 nightly, but I had to force the padding on x-column-header-inner to avoid Ext's auto-padding of top/bottom to valign center the text. Else the column filter would get pushed down out of view because of the padding.

.x-group-sub-header .x-column-header-inner {
padding: 3px 6px 5px !important;
}

I tried to make Ext aware of the new content we pushed into the column header, but couldn't seem to make it work. Ext just padded the text regardless of the container we added to it.

I also tried to change the container hoping Ext would then see the column filter; no dice.

shankar8rajah1
1 Nov 2013, 10:54 AM
getting error when I tried adding the plugin:

TypeError: k.push is not a function

Am I doing something wrong here?


var grid = Ext.create('Ext.grid.Panel', { border: false,
region: 'center',
//indexes:['name','service_group','azul_version', 'host_tech','ait_num','app_name','data_center','filer_mounts','instnaces','env'],
store: store,
columns: createHeaders(10),
loadMask: true,
features: [filters,searching],
width: 400,
layout: 'fit',
tbar: Ext.create('Ext.Toolbar'),
bbar: Ext.create('Ext.Toolbar'),
plugins: [Ext.create('Ext.ux.grid.plugin.HeaderFilters')],
enableTextSelection : true,
selModel: {
selType: 'cellmodel'
}
});

aerozep
2 Dec 2013, 12:06 PM
same error....
TypeError: result.push is not a function

result.push(item);

d.zucconi
31 Mar 2014, 2:08 AM
It works in 4.2 after I changed this in two places:

var columns = this.grid.headerCt.getGridColumns(true);

to this:

var columns = this.grid.headerCt.getGridColumns();

I'll need to go figure out what the 'true' was for and test with nested headers and other things though...but a few basic filters on a basic grid works.
Correct.
The prototype of method getGridColumns of Ext.grid.header.Container seems to be changed from ExtJS 4.1 to ExtJS 4.2:
http://docs.sencha.com/extjs/4.1.1/#!/api/Ext.grid.header.Container-method-getGridColumns
http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.grid.header.Container-method-getGridColumns
I think that the first parameter can be removed without problem as suggested.

Thanks

patfla
31 Mar 2014, 3:55 PM
Hi - I'm using 4.2.2. Upon loading HeaderFilters, the browser (both FF and Chrome) tells me that

this.grid.headerCt

is undefined.

Looked at the 4.2.2 docs for Ext.container.Container and I don't see headerCt.

d.zucconi
31 Mar 2014, 11:39 PM
Hi - I'm using 4.2.2. Upon loading HeaderFilters, the browser (both FF and Chrome) tells me that
this.grid.headerCt
is undefined.
Looked at the 4.2.2 docs for Ext.container.Container and I don't see headerCt.
headerCt is a working attribute of Ext.panel.Table, initialized by its initComponent method.
Unfortunately is not a documented private/protected variabile (so it could change or disappear with future versions of ExtJS) but it's the only way that I've found to access grid header containers (since ExtJS 4.x.x).
I don't know if in the latest API version exists a better way to access this container.
However I'm testing the plugin with the latest 4.2.2 and I've not found problems with this variable. I'm using "simple" grid only, without hierarchical headers or locked columns. Maybe you have a grid with special features or configuration ?

patfla
1 Apr 2014, 12:13 PM
Thanks Damiano.

I'm pretty much completely new to ExtJS, let alone Grid Headers Filter, and simply wanted to get something to display. Load, run, etc. I've been working off both my own ExtJS code as well example code upythread by prijithkr to tie together your code with my web site. Prijithkr said his code wasn't working but I haven't let that stop me.

I can get his grid and data to display by moving

plugins: [Ext.create('system.view.common.HeaderFilters')],

outside the Ext.create on grid panel to

requires: ['system.view.common.HeaderFilters'],

however that's pointless in that there's no grid filtering.

So I returned to plugins and now see


[Ext.Loader] Synchronously loading 'system.view.common.HeaderFilters'; consider adding Ext.require('system.view.common.HeaderFilters') above Ext.onReadyext-all-dev.js:9409 (http://nadc-eis11-vm.nadc.arm.com:8092/static/extjs/ext-all-dev.js)


Uncaught TypeError: Object #<error> has no method 'push'


which I could take as progress except that I think what ExtJS is telling is that it simply doesn't want to load HeaderFilters.js as a plugin.

EXTabhi
28 May 2014, 11:57 PM
Hello All,

We are trying to set the columns dynamically in the grid with below steps


var filterPlugin = Ext.create(
'Ext.grid.plugin.GridHeaderFilters',
{
pluginId:'gridHeaderFilterPlugin'

}) ;

grid.suspendEvents();
grid.reconfigure(forecastDataStore,myColumns);
filterPlugin.init(grid);
grid.plugins.push(filterPlugin);
grid.getPlugin('gridHeaderFilterPlugin').renderFilters();

grid.getView().refresh();
grid.resumeEvents();but the filters are disappearing , also we are getting the error

TypeError: k.push is not a functionsimilar to what is quoted in reply 74 by patflathanks to suggest on the same.

pratikbhat
3 Jul 2014, 7:51 PM
Does this plugin work fine with buffered store for infinite scrolling?
I am facing an issue wherein the scrollbar jumps a couple of rows on reaching the bottom rows, only when filters are active.

wki01
22 Jul 2014, 10:54 PM
Any plans to upgrade for 5 ExtJS?

thank you very much

qooleot
23 Jul 2014, 2:53 AM
" wki01
Any plans to upgrade for 5 ExtJS? "


I switched from using this plugin to the built-in items property of a column that takes an array of fields. It lacks event listeners (keyup to catch Enter key), and collection handling (set all fields, clear all fields) - so I've homebrewed a few things I need but it works well enough.

Proffnet
26 Nov 2014, 2:06 PM
You have to comment lines:
this.grid.addEvents{
....
}

since addEvents is deprecated (It's no longer needed to add events before firing.).

.. and change lines from:

this.grid.headerCt.getGridColumns(true);

to:

this.grid.headerCt.getGridColumns(false,true);


In extjs 5 getGridColumns method has two parameters (inResluts ,hidden...).
Hope it heps.