PDA

View Full Version : Grid header filters



d.zucconi
17 Jul 2008, 11:50 PM
This is a plugin that enables server-side filters for grid in columns headers. The plugin enables the new ColumnModel configuration option filter. This attribute value must be a valid Ext.form.Field component configuration or an array of filter configuration objects. The field becomes the filter field used into your column header.
The filter will affect Store request parameters, adding a new parameter to Store.baseParams.Parameter name can be specified in filter configuration using the filterName option. If not specified, the name will be equal to ColumnModel dataIndex.

An ExtJS 4 version of this plugin is developed and documented on this thread:
http://www.sencha.com/forum/showthread.php?150918-Grid-Header-Filters&p=660276#post660276

Versions:

1.0.0 - 12/1/09

Some bug fixes
Plugin now enables some new methods on grid such as "getHeaderFilter(name)" or
"getHeaderFilterField(name)"
Changed filters rendering
Added "filterEncoder" and "filterDecoder" cfg attributes. These parameters allow to enable functions to encode or decode filter value before and after store reload or grid status update
1.0.2 - 14/04/09

Some bug fixes (such as access to load parameters for grid store)
Fixed text selection support for TextField filters on Mozilla Firefox (-moz-user-select CSS property)
Filters header panel background color now is transparent (not white)
Added support for filter highlighting when at least one filter is active (useful if you have an active filter on the last column that could not be visibile without horizontal scroll)
1.0.5 - 13/07/09 (tested with Ext 3.0)

Added stateful configuration parameter to select if filters values should be saved with Ext.state.Provider. This parameter is true by default. Ex: new Ext.ux.grid.GridHeaderFilters({stateful: false}).
Fixed column auto-show if a filter has empty value
Changed and simplified filters rendering (see onRender())
Minor fixes and code cleaning (thanks to dzj)
1.0.6 - 30/07/09 (tested with Ext 3.0 - 3.0.1 - 3.0.2)

The plugin now enables for the grid the new method applyHeaderFilters.
Added applyMode configuration parameter to select if filters should be applied every time filter field value changes or only if user select to apply filters. If the value of this parameter is set to 'auto', filters are applied when each field value is changed (default, as previous versions). If the value is set to 'enter', the filters are applied only when the users hits the "ENTER" key on the filter field or when the grid method "applyHeaderFilters" is called (ex. add a button on your grid tbar and use this method as click handler). This would help when you need to change more than one filter before reloading the grid content.
1.0.9 - 29/10/09 (tested with Ext 3.0.0 up to 3.0.3)

The plugin now signals render event when filters rendering is done. This could be useful to load store only when filters are already initialized.
Added filters configuration parameter to initialize filters values at configuration time. These values will override values loaded from state (if filters are stateful)
Fixed bug for store reload on column move.
1.0.12 - 06/08/10 (tested with Ext 3.1.2)

Added applyFilterEvent filter configuration parameter. Allows developers to choose the field-event that applies filter value.
Added ensureFilteredVisible plugin configuration parameter.
Fixed some bugs. Thanks to ob1, dolittle and dzj.
2.0.3 - 23/12/10 (tested with Ext 3.3.1)

The plugin now supports more than one filter for each column. The value for the filter column model attribute can be an array of field configurations (with specific filterName for each field)
Changed highlight filter mode and introduced highlightCls configuration parameter
EXPERIMENTAL support for grid reconfiguration: the plugin now intercepts grid reconfigure event to reconfigure and render filters.
Code rewritten, simplified filters render, compatible with Ext 3.3.0
2.0.5 - 25/02/11 (tested with Ext 3.3.1)

Filter values specified into filters config parameter are removed if doesn't match with any available filter field
Fixed destroy memory leak caused by typo (thanks to qwikso)
2.0.6 - 03/03/11

Fixed disabled filter field support (thanks to dolittle)


Usage:
Create a new instance of Ext.ux.grid.GridHeaderFilters and put it into your grid plugins list
Define filter configuration with filter configuration attribute in ColumnModel configuration
Configuration example:



var gridCfg = {
xtype: "grid",
store: articleStore,
plugins: [new Ext.ux.grid.GridHeaderFilters()],
cm: new Ext.grid.ColumnModel([{
header : "Code",
width: 120,
sortable: true,
dataIndex: "CODE",
filter: {xtype:"textfield", filterName:"CODE"}
},{
id: "ART_DESC",
header: "Description",
width: 300,
sortable: true,
dataIndex: "ART_DESC",
filter: [{xtype:"textfield"},{xtype:"textfield"}]
},{
id: "TYPE_DESC",
header: "Type",
width: 100,
sortable: false,
dataIndex: "TYPE_DESC",
filter: {
xtype: "combo",
mode: "local",
store: [["A","Type1"],["B","Type2"]],
triggerAction: "all"
}

}])
}



Source code (version 2.0.6):



Ext.namespace("Ext.ux.grid");

/**
* @class Ext.ux.grid.GridHeaderFilters
* @extends Ext.util.Observable
*
* Plugin that enables filters in columns headers.
*
* To add a grid header filter, put the "filter" attribute in column configuration of the grid column model.
* This attribute is the configuration of the Ext.form.Field to use as filter in the header or an array of fields configurations.<br>
* <br>
* The filter configuration object can include some special attributes to manage filter configuration:
* <ul>
* <li><code>filterName</code>: to specify the name of the filter and the corresponding HTTP parameter used to send filter value to server.
* If not specified column "dataIndex" attribute will be used, if more than one filter is configured for the same column, the filterName will be the "dataIndex" followed by filter index (if index &gt; 0)</li>
* <li><code>value</code>: to specify default value for filter. If no value is provided for filter (in <code>filters</code> plugin configuration parameter or from loaded status),
* this value will be used as default filter value</li>
* <li><code>filterEncoder</code>: a function used to convert filter value returned by filter field "getValue" method to a string. Useful if the filter field getValue() method
* returns an object that is not a string</li>
* <li><code>filterDecoder</code>: a function used to convert a string to a valid filter field value. Useful if the filter field setValue(obj) method
* needs an object that is not a string</li>
* <li><code>applyFilterEvent</code></li>: a string that specifies the event that starts filter application for this filter field. If not specified, the "applyMode" is used. (since 1.0.10)</li>
* </ul>
* <br>
* Filter fields are rendered in the header cells within an <code>Ext.Panel</code> with <code>layout='form'</code>.<br>
* For each filter you can specify <code>fieldLabel</code> or other values supported by this layout type.<br>
* You can also override panel configuration using <code>containerConfig</code> attribute.<br>
* <br>
* This plugin enables some new grid methods:
* <ul>
* <li>getHeaderFilter(name)</li>
* <li>getHeaderFilterField(name)</li>
* <li>setHeaderFilter(name, value)</li>
* <li>setHeaderFilters(object, [bReset], [bReload])</li>
* <li>resetHeaderFilters([bReload])</li>
* <li>applyHeaderFilters([bReload])</li>
* </ul>
* The "name" is the filterName (see filterName in each filter configuration)
*
* @author Damiano Zucconi - http://www.isipc.it
* @version 2.0.6 - 03/03/2011
*/
Ext.ux.grid.GridHeaderFilters = function(cfg){if(cfg) Ext.apply(this, cfg);};

Ext.extend(Ext.ux.grid.GridHeaderFilters, Ext.util.Observable,
{
/**
* @cfg {Number} fieldHeight
* Height for each filter field used by <code>autoHeight</code>.
*/
fieldHeight: 22,

/**
* @cfg {Number} padding
* Padding for filter fields. Default: 2
*/
fieldPadding: 1,

/**
* @cfg {Boolean} highlightOnFilter
* Enable grid header highlight if active filters
*/
highlightOnFilter: true,

/**
* @cfg {String} highlightColor
* Color for highlighted grid header
*/
highlightColor: 'yellow',

/**
* @cfg {String} highlightCls
* Class to apply to filter header when filters are highlighted. If specified overrides highlightColor.
* See <code>highlightOnFilter</code>.
*/
highlightCls: null,

/**
* @cfg {Boolean} stateful
* Enable or disable filters save and restore through enabled Ext.state.Provider
*/
stateful: true,

/**
* @cfg {String} applyMode
* Sets how filters are applied. If equals to "auto" (default) the filter is applyed when filter field value changes (change, select, ENTER).
* If set to "enter" the filters are applied only when user push "ENTER" on filter field.<br>
* See also <code>applyFilterEvent</code> in columnmodel filter configuration: if this option is specified in
* filter configuration, <code>applyMode</code> value will be ignored and filter will be applied on specified event.
* @since Ext.ux.grid.GridHeaderFilters 1.0.6
*/
applyMode: "auto",

/**
* @cfg {Object} filters
* Initial values for filters (mapped with filters names). If this object is defined,
* its attributes values overrides the corresponding filter values loaded from grid status or <code>value</code> specified in column model filter configuration.<br>
* Values specified into column model configuration (filter <code>value</code> attribute) are ignored if this object is specified.<br>
* See <code>filtersInitMode</code> to understand how these values are mixed with values loaded from grid status.
* @since Ext.ux.grid.GridHeaderFilters 1.0.9
*/
filters: null,

/**
* @cfg {String} filtersInitMode
* If <code>filters</code> config value is specified, this parameter defines how these values are used:
* <ul>
* <li><code>replace</code>: these values replace all values loaded from grid status (status is completely ignored)</li>
* <li><code>merge</code>: these values overrides values loaded from status with the same name. Other status values are keeped and used to init filters.</li>
* </ul>
* This parameter doesn't affect how filter <code>value</code> attribute is managed: it will be always ignored if <code>filters</code> object is specified.<br>
* Default = 'replace'
*/
filtersInitMode: 'replace',

/**
* @cfg {Boolean} ensureFilteredVisible
* If true, forces hidden columns to be made visible if relative filter is set. Default = true.
*/
ensureFilteredVisible: true,

cfgFilterInit: false,

/**
* @cfg {Object} containerConfig
* Base configuration for filters container of each column. With this attribute you can override filters <code>Ext.Container</code> configuration.
*/
containerConfig: null,

/**
* @cfg {Number} labelWidth
* Label width for filter containers Form layout. Default = 50.
*/
labelWidth: 50,

fcc: null,

filterFields: null,

filterContainers: null,

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

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

var gv = this.grid.getView();
gv.updateHeaders = gv.updateHeaders.createSequence(function(){
this.renderFilters.call(this);
},this).createInterceptor(function(){
this.destroyFilters.call(this);
return true;
},this);
this.grid.on({
scope: this,
render: this.onRender,
resize: this.onResize,
columnresize: this.onColResize,
reconfigure: this.onReconfigure,
beforedestroy: this.destroyFilters
});
//this.grid.on("columnmove", this.renderFilters, this);
if(this.stateful)
{
this.grid.on("beforestatesave", this.saveFilters, this);
this.grid.on("beforestaterestore", this.loadFilters, this);
}

//Column hide event managed
this.grid.getColumnModel().on("hiddenchange", this.onColHidden, this);

this.grid.addEvents(
/**
* @event filterupdate
* <b>Event enabled on the GridPanel</b>: fired when a filter is updated
* @param {String} name Filter name
* @param {Object} value Filter value
* @param {Ext.form.Field} el Filter field
*/
'filterupdate');

this.addEvents(
/**
* @event render
* Fired when filters render on grid header is completed
* @param {Ext.ux.grid.GridHeaderFilters} this
*/
{'render': true}
);

//Must ignore filter config value ?
this.cfgFilterInit = Ext.isDefined(this.filters) && this.filters !== null;
if(!this.filters)
this.filters = {};

//Configuring filters
this.configure(this.grid.getColumnModel());

Ext.ux.grid.GridHeaderFilters.superclass.constructor.call(this);

if(this.stateful)
{
if(!Ext.isArray(this.grid.stateEvents))
this.grid.stateEvents = [];
this.grid.stateEvents.push('filterupdate');
}

//Enable new grid methods
Ext.apply(this.grid, {
headerFilters: this,
getHeaderFilter: function(sName){
if(!this.headerFilters)
return null;
return this.headerFilters.filters[sName];
},
setHeaderFilter: function(sName, sValue){
if(!this.headerFilters)
return;
var fd = {};
fd[sName] = sValue;
this.setHeaderFilters(fd);
},
setHeaderFilters: function(obj, bReset, bReload)
{
if(!this.headerFilters)
return;
if(bReset)
this.resetHeaderFilters(false);
if(arguments.length < 3)
var bReload = true;
var bOne = false;
for(var fn in obj)
{
if(this.headerFilters.filterFields[fn])
{
var el = this.headerFilters.filterFields[fn];
this.headerFilters.setFieldValue(el,obj[fn]);
this.headerFilters.applyFilter(el, false);
bOne = true;
}
}
if(bOne && bReload)
this.headerFilters.storeReload();
},
getHeaderFilterField: function(fn)
{
if(!this.headerFilters)
return;
if(this.headerFilters.filterFields[fn])
return this.headerFilters.filterFields[fn];
else
return null;
},
resetHeaderFilters: function(bReload)
{
if(!this.headerFilters)
return;
if(arguments.length == 0)
var bReload = true;
for(var fn in this.headerFilters.filterFields)
{
var el = this.headerFilters.filterFields[fn];
if(Ext.isFunction(el.clearValue))
{
el.clearValue();
}
else
{
this.headerFilters.setFieldValue(el, '');
}
this.headerFilters.applyFilter(el, false);
}
if(bReload)
this.headerFilters.storeReload();
},
applyHeaderFilters: function(bReload)
{
if(arguments.length == 0)
var bReload = true;
this.headerFilters.applyFilters(bReload);
}
});

},

/**
* @private
* Configures filters and containers starting from grid ColumnModel
* @param {Ext.grid.ColumnModel} cm The column model to use
*/
configure: function(cm)
{
/*Filters config*/
var filteredColumns = cm.getColumnsBy(function(cc){
if(Ext.isObject(cc.filter) || Ext.isArray(cc.filter))
return true;
else
return false;
});

/*Building filters containers configs*/
this.fcc = {};
for (var i = 0; i < filteredColumns.length; i++)
{
var co = filteredColumns[i];
var fca = co.filter;
if(!Ext.isArray(fca))
fca = [fca];
for(var ci = 0; ci < fca.length; ci++)
{
var fc = Ext.apply({
filterName: ci > 0 ? co.dataIndex+ci : co.dataIndex
},fca[ci]);
Ext.apply(fc, {
columnId: co.id,
dataIndex: co.dataIndex,
hideLabel: Ext.isEmpty(fc.fieldLabel),
anchor: '100%'
});

if(!this.cfgFilterInit && !Ext.isEmpty(fc.value))
{
this.filters[fc.filterName] = Ext.isFunction(fc.filterEncoder) ? fc.filterEncoder.call(this, fc.value) : fc.value;
}
delete fc.value;

/*
* Se la configurazione del field di filtro specifica l'attributo applyFilterEvent, il filtro verrà applicato
* in corrispondenza di quest'evento specifico
*/
if(fc.applyFilterEvent)
{
fc.listeners = {scope: this};
fc.listeners[fc.applyFilterEvent] = function(field){this.applyFilter(field);};
delete fc.applyFilterEvent;
}
else
{
//applyMode: auto o enter
if(this.applyMode === 'auto' || this.applyMode === 'change' || Ext.isEmpty(this.applyMode))
{
//Legacy mode and deprecated. Use applyMode = "enter" or applyFilterEvent
fc.listeners =
{
change: function(field)
{
var t = field.getXType();
if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
return;
}else{
this.applyFilter(field);
}
},
specialkey: function(el,ev)
{
ev.stopPropagation();
if(ev.getKey() == ev.ENTER)
el.el.dom.blur();
},
select: function(field){this.applyFilter(field);},
scope: this
};
}
else if(this.applyMode === 'enter')
{
fc.listeners =
{
specialkey: function(el,ev)
{
ev.stopPropagation();
if(ev.getKey() == ev.ENTER)
{
this.applyFilters();
}
},
scope: this
};
}
}

//Looking for filter column index
var containerCfg = this.fcc[fc.columnId];
if(!containerCfg)
{
containerCfg = {
cls: this.filterContainerCls,
border: false,
bodyBorder: false,
/*layout: 'vbox',
layoutConfig: {align: 'stretch', padding: this.padding},*/
labelSeparator: '',
labelWidth: this.labelWidth,
layout: 'form',
style: {},
items: []
};
if(this.containerConfig)
Ext.apply(containerCfg, this.containerConfig);
this.fcc[fc.columnId] = containerCfg;
}
containerCfg.items.push(fc);
}
}
},

renderFilterContainer: function(columnId, fcc)
{
if(!this.filterContainers)
this.filterContainers = {};
//Associated column index
var ci = this.grid.getColumnModel().getIndexById(columnId);
//Header TD
var td = this.grid.getView().getHeaderCell(ci);
td = Ext.get(td);
//Patch for field text selection on Mozilla
if(Ext.isGecko)
td.dom.style.MozUserSelect = "text";
td.dom.style.verticalAlign = 'top';
//Render filter container
fcc.width = td.getWidth() - 3;
var fc = new Ext.Container(fcc);
fc.render(td);
//Container cache
this.filterContainers[columnId] = fc;
//Fields cache
var height = 0;
if(!this.filterFields)
this.filterFields = {};
var fields = fc.findBy(function(cmp){return !Ext.isEmpty(cmp.filterName);});
if(!Ext.isEmpty(fields))
{
for(var i=0;i<fields.length;i++)
{
var filterName = fields[i].filterName;
/*if(this.filterFields[filterName])
{
//Ext.destroy(this.filterFields[filterName])
delete this.filterFields[filterName];
}*/
this.filterFields[filterName] = fields[i];
height += fields[i].getHeight();
}
}

return fc;
},

renderFilters: function()
{
if(!this.fcc)
return;
for(var cid in this.fcc)
{
this.renderFilterContainer(cid, this.fcc[cid]);
}
this.setFilters(this.filters);
this.highlightFilters(this.isFiltered());
},

onRender: function()
{
this.renderFilters();
if(this.isFiltered())
{
this.applyFilters(false);
}
this.fireEvent("render", this);
},

getFilterField: function(filterName)
{
return this.filterFields ? this.filterFields[filterName] : null;
},

/**
* Sets filter values by values specified into fo.
* @param {Object} fo Object with attributes filterName = value
* @param {Boolean} clear If current values must be cleared. Default = false
*/
setFilters: function(fo,clear)
{
this.filters = fo;

if(this.filters && this.filterFields)
{
//Delete filters that doesn't match with any field
for(var fn in this.filters)
{
if(!this.filterFields[fn])
delete this.filters[fn];
}

for(var fn in this.filterFields)
{
var field = this.filterFields[fn];
var value = this.filters[field.filterName];
if(Ext.isEmpty(value))
{
if(clear)
this.setFieldValue(field, '');
}
else
this.setFieldValue(field, value);
}
}
},

onColResize: function(index, iWidth){
if(!this.filterContainers)
return;
var colId = this.grid.getColumnModel().getColumnId(index);
var cnt = this.filterContainers[colId];
if(cnt)
{
if(isNaN(iWidth))
iWidth = 0;
var filterW = (iWidth < 3) ? 0 : (iWidth - 3);
cnt.setWidth(filterW);
//Thanks to ob1
cnt.doLayout(false,true);
}
},

/**
* @private
* Resize filters containers on grid resize
* Thanks to dolittle
*/
onResize: function()
{
var n = this.grid.getColumnModel().getColumnCount();
for(var i=0; i<n; i++) {
var td = this.grid.getView().getHeaderCell(i);
td = Ext.get(td);
this.onColResize(i, td.getWidth());
}
},

onColHidden: function(cm, index, bHidden){
if(bHidden)
return;
var cw = this.grid.getColumnModel().getColumnWidth(index);
this.onColResize(index, cw);
},

onReconfigure: function(grid, store, cm)
{
this.destroyFilters();
this.configure(cm);
this.renderFilters();
},

saveFilters: function(grid, status)
{
var vals = {};
for(var name in this.filters)
{
vals[name] = this.filters[name];
}
status["gridHeaderFilters"] = vals;
return true;
},

loadFilters: function(grid, status)
{
var vals = status.gridHeaderFilters;
if(vals)
{
if(this.cfgFilterInit)
{
if(this.filtersInitMode === 'merge')
Ext.apply(vals,this.filters);
}
else
this.filters = vals;
}
},

isFiltered: function()
{
for(var k in this.filters)
{
if(/*this.filterFields && this.filterFields[k] && */!Ext.isEmpty(this.filters[k]))
return true;
}
return false;
},

highlightFilters: function(enable)
{
if(!this.highlightOnFilter)
return;
if(!this.filterContainers)
return;
if(!this.grid.getView().mainHd)
return;

var tr = this.grid.getView().mainHd.child('.x-grid3-hd-row');
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
tr.addClass(this.highlightCls);
else
tr.removeClass(this.highlightCls);
}
else
{
tr.setStyle('background-color',enable ? this.highlightColor : '');
}
/*for(var i=0; i < this.grid.getColumnModel().getColumnCount(); i++)
{
var hc = Ext.get(this.grid.getView().getHeaderCell(i));
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
hc.addClass(this.highlightCls);
else
hc.removeClass(this.highlightCls);
}
else
{
hc.setStyle('background-color',enable ? this.highlightColor : 'transparent');
}
}*/
/*var color = enable ? this.highlightColor : 'transparent';
for(var fn in this.filterContainers)
{
var fc = this.filterContainers[fn];
if(fc.rendered)
{
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
fc.getEl().addClass(this.highlightCls);
else
fc.getEl().removeClass(this.highlightCls);
}
else
fc.getEl().setStyle('backgroundColor',color);
}
}*/
},

getFieldValue: function(eField)
{
if(Ext.isFunction(eField.filterEncoder))
return eField.filterEncoder.call(eField, eField.getValue());
else
return eField.getValue();
},

setFieldValue: function(eField, value)
{
if(Ext.isFunction(eField.filterDecoder))
value = eField.filterDecoder.call(eField, value);
eField.setValue(value);
},

applyFilter: function(el, bLoad)
{
if(arguments.length < 2)
bLoad = true;
if(!el)
return;

if(!el.isValid())
return;

if(el.disabled && !Ext.isDefined(this.grid.store.baseParams[el.filterName]))
return;

var sValue = this.getFieldValue(el);

if(el.disabled || Ext.isEmpty(sValue))
{
delete this.grid.store.baseParams[el.filterName];
delete this.filters[el.filterName];
}
else
{
this.grid.store.baseParams[el.filterName] = sValue;
this.filters[el.filterName] = sValue;

if(this.ensureFilteredVisible)
{
//Controllo che la colonna del filtro applicato sia visibile
var ci = this.grid.getColumnModel().getIndexById(el.columnId);
if((ci >= 0) && (this.grid.getColumnModel().isHidden(ci)))
this.grid.getColumnModel().setHidden(ci, false);
}
}

//Evidenza filtri se almeno uno attivo
this.highlightFilters(this.isFiltered());

this.grid.fireEvent("filterupdate",el.filterName,sValue,el);

if(bLoad)
this.storeReload();
},

applyFilters: function(bLoad)
{
if(arguments.length < 1)
bLoad = true;
for(var fn in this.filterFields)
{
this.applyFilter(this.filterFields[fn], false);
}
if(bLoad)
this.storeReload();
},

storeReload: function()
{
if(!this.grid.store.lastOptions)
return;
var slp = {start: 0};
if(this.grid.store.lastOptions.params && this.grid.store.lastOptions.params.limit)
slp.limit = this.grid.store.lastOptions.params.limit;
this.grid.store.load({params: slp});
},

getFilterContainer: function(columnId)
{
return this.filterContainers ? this.filterContainers[columnId] : null;
},

destroyFilters: function()
{
if(this.filterFields)
{
for(var ff in this.filterFields)
{
Ext.destroy(this.filterFields[ff]);
delete this.filterFields[ff];
}
}

if(this.filterContainers)
{
for(var ff in this.filterContainers)
{
Ext.destroy(this.filterContainers[ff]);
delete this.filterContainers[ff];
}
}

}
});

mjlecomte
18 Jul 2008, 5:09 AM
Wow, nice first post!?

MeDavid
18 Jul 2008, 11:26 AM
Looking nice. Contrary to other filter extensions you see the filter values at all times. Looking forward to some date from/to support :)

d.zucconi
21 Jul 2008, 1:03 AM
Looking forward to some date from/to support :)
Well, I know... the "period" filter is a need for me too.
To support this kind of filter I'm thinking to develop (in the future :) ) a simple widget that groups 2 DateField. The getValue() method of this widget would return an object (or the equivalent JSON string) with 2 attributes (ex. {begin: "20080720", end: "20080820"} or {begin: "", end: "20080820"}). Then you can add this widget into your header filters.

I've already developed a similar widget to support "checkboxes filter" (see the attachment). This is only a simple (and, sorry, undocumented) example, but it works fine in my use-cases.

Jets
22 Aug 2008, 1:29 AM
Nice!But have some bugs,when the cols hidden,you need to resize the ColumnModel.My English is not good,Sorry :)

nanich
23 Aug 2008, 1:19 AM
hi,
Thank you very much for this great plugin. As per my requirement i need to show the filter field up above the header label instead of downside that is there in the plugin that you've provided. I tried to do this

Ext.get(headerDiv).createChild({id: "col-"+colCfg.id+"-filter-div", tag: "div"},Ext.get(headerDiv).dom.childNodes[0])

When i did this, the filter fields are getting rendered as per my requirement. But the problems that i've got are as follows
1. I could not able to see the header menu's icon which will come beside the header when we mouseover on it.
2. When i try to move the column by drag & drop of column label, I could not able to see the header label in the flyout that will come along with the mouse.

Please help in solving this problem. Thanks in advance.

ExtMike
5 Feb 2009, 2:19 PM
Hello,

I wanted to test the GridHeaderFilters example (on Ext 2.2.1) and got stuck (I'm a beginner...). Can you please provide a ready-to-run example? I'm getting the error "sp is undefined" in ext-base.js

Thanks!

d.zucconi
5 Feb 2009, 11:56 PM
Hi,

I've updated code version on the first page of this post (1.0.0 12/1/09).
I've removed the zip attachment and reported plugin code directly in the message.
This is the latest version of my plugin and is the same version I'm currently using in my webapps.
About your error is hard to say for me what could be the cause... :-?
A valid usage example is the grid code reported in the "Configuration example" on the first page... However you could post your code to check if I can help you directly with your problem

jsakalos
6 Feb 2009, 12:09 AM
Have you ever seen this? http://extjs.com/forum/showthread.php?p=33434 ?

Could you please post link to a demo?

d.zucconi
6 Feb 2009, 12:32 AM
Could you please post link to a demo?
Sorry, but at the moment I don't have an online example. I'll try to publish something ASAP.

jsakalos
6 Feb 2009, 12:33 AM
OK, looking forward... :)

ExtMike
9 Feb 2009, 12:44 AM
Hello,

now it's fine. Your plugin works!
The cause of the problems was Jetty, it locks static content files (e.g Javascript). UltraEdit saved my changes to the .js file anyway but the result was mixed up and produced some strange Javascript errors...
After correcting this, I could easily extend my existing grid with your plugin.

To anyone who develops with Jetty, set useFileMappedBuffer to false in the webdefault.xml file.

Thanks!
Mike

ExtMike
2 Mar 2009, 1:33 AM
Hello,
I have some questions to the Grid header filter:
The text within a header textfield cannot be selected completely by double click. Usually, if you want to change the filter, you double click in it so the text is completely selected. Then you type the new text and the old is removed.
Another problem: The textfield is too small. How can you set the width of the textfield so it has the width of the column?
I'm using Firefox and Safari 4

jsakalos
24 Mar 2009, 9:13 AM
Sorry, but at the moment I don't have an online example. I'll try to publish something ASAP.

Not yet?

dzj
26 Mar 2009, 7:00 PM
storeReload: function()
{
/*if(!Ext.isEmpty(this.grid.store.baseParams["limit"]))
{
this.grid.store.baseParams.start = 0;
}*/
if(!this.grid.store.lastOptions)
return;
var slp = {start: 0};
if(this.grid.store.lastOptions.params.limit)
slp.limit = this.grid.store.lastOptions.params.limit
this.grid.store.load({params: slp});
},

modified to:


storeReload: function()
{
/*if(!Ext.isEmpty(this.grid.store.baseParams["limit"]))
{
this.grid.store.baseParams.start = 0;
}*/
if(!this.grid.store.lastOptions)
return;
var slp = {start: 0};
if((typeof this.grid.store.lastOptions.params != 'undefined') && (typeof this.grid.store.lastOptions.params.limit != 'undefined') )
slp.limit = this.grid.store.lastOptions.params.limit
this.grid.store.load({params: slp});
},

d.zucconi
14 Apr 2009, 8:14 AM
Not yet?
Sorry to keep you waiting :s (problems with public host).

Now I've published on first page the live example URL:
http://84.253.168.37:8090/w2p/docs.html

Cheers

d.zucconi
14 Apr 2009, 8:16 AM
storeReload: function()
{
/*if(!Ext.isEmpty(this.grid.store.baseParams["limit"]))
{
this.grid.store.baseParams.start = 0;
}*/
if(!this.grid.store.lastOptions)
return;
var slp = {start: 0};
if(this.grid.store.lastOptions.params.limit)
slp.limit = this.grid.store.lastOptions.params.limit
this.grid.store.load({params: slp});
},
modified to:


storeReload: function()
{
/*if(!Ext.isEmpty(this.grid.store.baseParams["limit"]))
{
this.grid.store.baseParams.start = 0;
}*/
if(!this.grid.store.lastOptions)
return;
var slp = {start: 0};
if((typeof this.grid.store.lastOptions.params != 'undefined') && (typeof this.grid.store.lastOptions.params.limit != 'undefined') )
slp.limit = this.grid.store.lastOptions.params.limit
this.grid.store.load({params: slp});
},

Thanks for the hint !
In the meanwhile I've solved the same problem as you can see on the first post page (version 1.0.2)

dzj
22 Apr 2009, 2:30 AM
createFilterPanel: function(colCfg, grid) { var iColIndex = this.cm.findColumnIndex(colCfg.dataIndex); ---->modified to createFilterPanel: function(colCfg, grid) { var iColIndex = this.cm.getIndexById(colCfg.id);

ttbgwt
15 May 2009, 9:28 AM
How would I create a checkbox filter for your plugin?

pdugas
20 May 2009, 9:51 AM
I'm loading the data in my grid from an Ext.ux.grid.livegrid.Store and am looking to add this filter plugin. When the page loads, it displays the grid header and the filter fields but then, once the data is loaded from the server, the header filters disappear. Any thoughts on where I've got amiss?

d.zucconi
21 May 2009, 10:17 PM
How would I create a checkbox filter for your plugin?
You can use something like this:
http://extjs.com/forum/showthread.php?t=32692
as input field for the filter.


...

filter:
{
xtype: "lovcombo",
triggerAction: "all",
mode: "local",
store: [[1,'A'],[2,'B'],[3,'C']]
}
...

d.zucconi
21 May 2009, 10:21 PM
I'm loading the data in my grid from an Ext.ux.grid.livegrid.Store and am looking to add this filter plugin. When the page loads, it displays the grid header and the filter fields but then, once the data is loaded from the server, the header filters disappear. Any thoughts on where I've got amiss?
I've never experienced this kind of problem... :-?
Also, I've never used Ext.ux.grid.livegrid.Store... Could you post your grid configuration code ?

ttbgwt
22 May 2009, 4:04 AM
I would like the filter to be a checkbox, and not a combo with checkbox selections...
xtype: checkbox

Thanks...


You can use something like this:
http://extjs.com/forum/showthread.php?t=32692
as input field for the filter.


...

filter:
{
xtype: "lovcombo",
triggerAction: "all",
mode: "local",
store: [[1,'A'],[2,'B'],[3,'C']]
}
...

ttbgwt
22 May 2009, 4:33 AM
Hi, our filters disappear as well when we move the columns around. Is there any way to reload the filters? Thanks! Below is an example of the code we use to move the columns and then the filters disappear...



var views = {
defaultView:
['id','ordername','ordertype','joblabel','companyname','contactfullname','salesfullname','orderstate','orderstage','orderstatus','lastupdated','total']
,
jobDetails:
['id','ordername','ordertype','joblabel','jobshipaddress1','jobshipcity','jobshipstateabbrev','jobshipzipcode','companyname','contactfullname','salesfullname','orderstate','orderstage','orderstatus','lastupdated','total']
}

var cm = orderhomeGrid.getColumnModel();
//iterate through defined view columns, moving and showing the desired cols in the right order
for (var i=0; i<view.length; i++)
{
//start at col 1 so that checkbox are always included and are first
var idx = cm.getIndexById(view[i]);
if (idx == -1){
firebugLog("Invalid column id in grid view definition: " + view[i]);
continue;
}
cm.moveColumn(idx, i+1);
cm.setHidden(i+1, false);
}
//now hide the rest of the columns
for (var i=view.length+1; i<cm.getColumnCount()-1; i++)
{
cm.setHidden(i, true);
}


I've never experienced this kind of problem... :-?
Also, I've never used Ext.ux.grid.livegrid.Store... Could you post your grid configuration code ?

d.zucconi
11 Jun 2009, 7:39 AM
Hi, our filters disappear as well when we move the columns around. Is there any way to reload the filters? Thanks! Below is an example of the code we use to move the columns and then the filters disappear...
You could simply call onRender() method of GridHeaderFilters plugin after your column movements are done.
Check the source code: this is the same action taken on "columnmove" event...

ttbgwt
15 Jun 2009, 5:27 AM
Thanks, that worked! Now I'm having a similar issue when I resize a column. The column in question resizes fine, but the other columns do not resize. I then tried calling the onRender after a resize but all of the columns resize in width but they grow in height two-fold, each time a column resize occurs?

jfvwi
22 Jun 2009, 12:13 PM
Have you seen an instance where the fields are missing in the header?

I just added the plug-in to a standard grid and the grid works fine, but the header doesn't contain any input fields.

Thanks for the help.

-John

jfvwi
22 Jun 2009, 1:32 PM
Nevermind - very easy to figure out - I didn't have any filters attached to the columns - after looking at the source I realized they weren't created on the fly. :))

ttbgwt
15 Jul 2009, 5:36 AM
I would like to show or hide the filters on demand from a button. Do you have a code example on how to show and hide the filters on demand? Thanks!

ttbgwt
15 Jul 2009, 11:45 AM
I figured it out... This worked for me:


this.grid.toggleHeaderFilters = function(bShow)
{
if(!this.headerFilters)
return;
if(arguments.length == 0)
var bShow = true;
for(var hc in this.headerFilters.headerCells)
{
var headerCell = this.headerFilters.headerCells[hc];
for(var cc in headerCell.children)
{
if (cc>0)
{
var child = headerCell.children[cc];
if (bShow)
{
child.style.height = this.headerFilters.height - (this.headerFilters.padding * 2) + 'px';
}
else
{
child.style.height = '0px';
}
}
}
}
}

hankin
31 Aug 2009, 2:27 PM
When I move columns I am noticing that the original div tag that defined the height is not being removed. Which, is making the header have twice the height it should. I think it happening because this.panels[co.dataIndex] = this.createFilterPanel(co, this.grid); is being called on both renders and on column moves. Does anybody have a solution for this?

onRender: function()
{
if(!this.filters)
this.filters = {};

this.filterFields = {};

//Elimino pannelli esistenti
for(var pId in this.panels)
{
if((this.panels[pId] != null) && (Ext.type(this.panels[pId].destroy) == "function"))
this.panels[pId].destroy();
}
this.panels = [];

this.cm = this.grid.getColumnModel();
this.gridView = this.grid.view;
this.headTr = Ext.DomQuery.selectNode("tr",this.gridView.mainHd.dom);
this.headerCells = Ext.query("td",this.headTr);

var cols = this.cm.getColumnsBy(function(){return true});
for ( var i = 0; i < cols.length; i++)
{
var co = cols[i];
this.panels[co.dataIndex] = this.createFilterPanel(co, this.grid);
}
//Evidenza filtri se almeno uno attivo
this.highlightFilters(this.isFiltered());

},

d.zucconi
3 Sep 2009, 4:32 AM
Hi,

The problem of duplicated divs on column move is solved with the latest version (1.0.5):
In this version the function createFilterPanel has been modified to avoid use of new DIVs and render filter panel directly into the header table cell.
So if you move the column, the panel will be destroyed and re-created (without supporting DIVs).



createFilterPanel: function(colCfg, grid)
{
// = this.cm.findColumnIndex(colCfg.dataIndex);
//Thanks to dzj
var iColIndex = this.cm.getIndexById(colCfg.id);
//var headerTd = Ext.get(this.gridView.getHeaderCell(iColIndex));
var headerTd = Ext.get(this.headerCells);
//Patch for field text selection on Mozilla
if(Ext.isGecko)
headerTd.dom.style.MozUserSelect = "text";
[I]//var filterPanelDiv = headerTd.createChild({id: Ext.id(), tag: "div"});
//filterPanelDiv.setHeight(this.height);
var filterPanel = null;

if(colCfg.filter)
{
var iColWidth = this.cm.getColumnWidth(iColIndex);
var iPanelWidth = iColWidth - 2;

//Pannello filtri
var panelConfig = {
/*id: "filter-panel-"+colCfg.id,*/
renderTo: headerTd,
width: iPanelWidth,
See first page of this thread to get the full code.

hankin
3 Sep 2009, 5:15 AM
Thanks that was a lot cleaner than the solution I came up with. I was searching and finding the old div than deleting it. Rendering the new div to that old div is way cleaner.

el_crespo
8 Sep 2009, 12:05 PM
Hello!! thanks for the extension.. but I have a question: ¿this works with EditorGridPanel and ext 3.0?
sorry for my English!!

Edit:

Now I Know that this works with EditorGridPanel and ext 3.0 but does not work if the grid have the next cod:


viewConfig : {
autoFill : true,
forceFit : false
}

captainkebab
24 Sep 2009, 12:20 AM
Great work!

But I have one problem: I use several combo-box filters and when I change their value the store gets reloaded two times.
The first time on clicking the item in the combo box and a second time when I "leave" the combo box by clicking on another filter or the page background. This is a little anoying.

So a check, if the value of the filter has changed since the last reload would be useful.
This could also prevent from reloading the store, when you click on the combo-box item that is already selected.

Any help would be appreciated.

calavera
26 Sep 2009, 3:18 PM
Does this work with ExtJS 3 ?

Thanks.

d.zucconi
1 Oct 2009, 5:57 AM
Does this work with ExtJS 3 ?

Thanks.
Yes, since version 1.0.5

d.zucconi
1 Oct 2009, 6:02 AM
Great work!

But I have one problem: I use several combo-box filters and when I change their value the store gets reloaded two times.
The first time on clicking the item in the combo box and a second time when I "leave" the combo box by clicking on another filter or the page background. This is a little anoying.

So a check, if the value of the filter has changed since the last reload would be useful.
This could also prevent from reloading the store, when you click on the combo-box item that is already selected.

Any help would be appreciated.
With version 1.0.6 you can use config parameter

applyMode: 'enter'
and add an "apply filters" button to your grid tbar to call "applyHeaderFilters" method (enabled in the grid by the plugin) to allow the user to choose when filters values are ready to be applied...

nickweavers
2 Nov 2009, 4:35 PM
Brilliant plugin!

I'm fairly new to this so please excuse me if I am missing a trick here and making this far more complicated than it needs to be.

When doing server side sorts, I see that I am getting the name of the dataIndex field as the key in $_POST along with the filter string as the value. Eg $_POST['last_name']='smith'. There doesn't seem to be any easy way for me to recognise this field as a filter.

To make it easier to plug straight into a server side query it would be nice if it were sent as something like a list of key/value pairs, one for the name of the field, and the other for its filter string, eg

$_POST['filter']=[
{field: 'first_name', value: 'john'},
{field: 'last_name', value: 'smith'}]

This way I can easily json_decode() the $_POST and iterate over the resulting array to build the filter part of my sql query.

Or is there a simple way for me to figure out what $_POST['last_name']='smith' was sent for?

TIA,
Nick.

alien3d
2 Nov 2009, 5:07 PM
I build php code for filtering and make searching like this in normal form.This code below is for php if anybody want to implement searching via sql.I will test this night this extension if work with my current application php.At first i tough want to used grid filter.Found this more better lor.


<?php
function search_javascript($variable_array) {
print"var url;\n";
print"url=\"".basename($_SERVER['PHP_SELF'])."?&search=1&mode=".$_GET['mode']."&sn=".$_GET['sn']."&action=".$_GET['action']."&id=\";\n";
foreach($variable_array as $variable_javascript) {
echo "var ".$variable_javascript.";\n";
echo $variable_javascript."=document.contractor_enquiry_form.".$variable_javascript.".value;\n";
echo "if(".$variable_javascript.".length > 0 ) { url=url+\"&".$variable_javascript."=\"+escape(".$variable_javascript."); } \n";
}
print"window.location.replace(url);\n";
}

function searching_text($string) {
$pos = strpos("~", $string);
if ($pos === false) {
return explode("~",$string);
}
}

function searching_text1($string) {
$pos = strpos(",", $search);
if ($pos === false) {
return explode(",",$string);
}
}

function searching_equal($string) {
$pos = strpos($string, $search);
if ($pos === false) {
return explode("=",$string);
}
}

function searching_lt($string) {
$pos = strpos($string, $search);
if ($pos === false) {
$value=explode("<=",$string);
if(count($value)== 2) {
return "lt";
} else {
return 'N';
}
} else {
return 'N';
}
}

function searching_mt($string) {
$pos = strpos(">=", $search);
if ($pos === false) {
$value=explode(">=",$string);
if(count($value)== 2) {
return "mt";
} else {
return 'N';
}
} else {
return 'N';
}
}

function searching_l($string) {
$pos = strpos("<", $search);
if ($pos === false) {
$value=explode("<",$string);
if(count($value)== 2) {
return "l";
} else {
return 'N';
}
} else {
return 'N';
}
}

function searching_m($string) {
$pos = strpos(">", $search);
if ($pos === false) {
$value=explode(">",$string);
if(count($value)== 2) {
return "m";
} else {
return 'N';
}
} else {
return 'N';
}
}

function search_mode($sql,$table,$fieldname,$value,$datatype) {
$value=trim($value);
list($value1,$value2)=searching_text($value);
if(!empty($value1) && !empty($value2)) {
if($datatype=="date") {
$value1=ConvertToDisplayDate2($value1); $value2=ConvertToDisplayDate2($value2);
}
$sql.=" AND `".$table."`.`".$fieldname."` between '".$value1."' AND '".$value2."' "; $search="false";
}
if($datatype=="date") {
$value=ConvertToDisplayDate2($value);
}
$array_list=searching_text1($value);
if(count($array_list) > 1 ) {
$sql.=" AND `".$table."`.`".$fieldname."` IN (";
for($m=0;$m<count($array_list);$m++) {
$sql.="'".$array_list[$m]."'";
if($m !=(count($array_list) -1)) {
$sql.=",";
}
}
$sql=$sql.")"; $search="false";
}
$numerics=searching_lt($value);
if(strval($numerics)=='N') {
$numerics=searching_l($value);
}
if(strval($numerics)=='N') {
$numerics=searching_mt($value);
}
if(strval($numerics)=='N') {
$numerics=searching_m($value);
}
if(strval($numerics)=="lt") {
$sql.=" AND `".$table."`.`".$fieldname."` <= '".str_replace("<=","",$value)."'"; $search="false";
} elseif(strval($numerics)=="l") {
$sql.=" AND `".$table."`.`".$fieldname."` < '".str_replace("<","",$value)."'"; $search="false";
}
if(strval($numerics)=="mt") {
$sql.=" AND `".$table."`.`".$fieldname."` >= '".str_replace(">=","",$value)."'"; $search="false";
} elseif(strval($numerics)=="m") {
$sql.=" AND `".$table."`.`".$fieldname."` > '".str_replace(">","",$value)."'"; $search="false";
}
if($search !="false") {
if($_GET['search_type'] || $datatype=="date" ) {
$sql.=" AND `".$table."`.`".$fieldname."` ='".$value."'";
} else {

$sql.=" AND `".$table."`.`".$fieldname."` like '".$value."'";
}
}
return $sql;
}

?>

ecalo
4 Nov 2009, 2:00 PM
What a great plugin. I'm a newbie to ExtJS, I tried experimenting on this plugin and found a bug: When you reorder the columns, the grid store will reload TWICE. I have no idea where and how to fix this. It's annoying since it will contact the server twice.

d.zucconi
4 Nov 2009, 11:40 PM
When you reorder the columns, the grid store will reload TWICE.
This was a known bug... I suppose that was already fixed with latest released version (1.0.6).
What version have you tested ?

ecalo
5 Nov 2009, 7:19 AM
I just copied your code found in the first page.

d.zucconi
6 Nov 2009, 2:42 AM
I just copied your code found in the first page.
Sorry, the fix for this bug is only included in the latest version (1.0.9) 8-| .
So I've updated the first page with my latest plugin version. Try to update and check if now the problem is solved.

ecalo
6 Nov 2009, 5:37 AM
Sorry, the fix for this bug is only included in the latest version (1.0.9) 8-| .
So I've updated the first page with my latest plugin version. Try to update and check if now the problem is solved.

Very nice! The bug is now fixed. Thanks a lot.

nickweavers
7 Nov 2009, 8:00 AM
When I use this plugin in my grid, this is an example of what I get posted to me at the server (since my store has other baseParams)


controller opsuk_admin
first_name John
last_name Weaver
limit 5
start 0
task employee_records
view main

Currently, for the server side PHP to determine which are column filters, it has to have a knowledge of either what the dataindex names are (loop using inclusion) or what they are not (loop using exclusion). In either case, if fields are added or removed, the inclusion or exclusion set used to check against must be updated.

It would be helpful if the filter parms could be differentiated by prefixing them with string such as FILTER_ so that the server side PHP could recognise them easily and construct the WHERE clause more simply. This way, all the PHP has to "know" is the name of the prefix (which could be hard coded or passed as another baseParam).


controller opsuk_admin
FILTER_first_name John
FILTER_last_name Weaver
limit 5
start 0
task employee_records
view main


I am an ExtJs newcomer, so could someone tell me if this would be simple mod I could do myself, and if so, could you please give me some clues as to where to start looking.

Many thanks,
Nick.

hschaefer123
11 Feb 2010, 10:34 AM
Hi Nick,
i am using a DirectStore Implementation that forces to have a known amount of
baseParams like start, limit, sort, sortdir, filters[]

For this reason, i modified the plugin a little bit (code is from 1.0.6, because i've problems with 1.0.9)


applyFilter: function(el, bLoad)
...
if(Ext.isEmpty(sValue))
{
//delete this.grid.store.baseParams[el.filterName];
delete this.filters[el.filterName];
}
else
{
//this.grid.store.baseParams[el.filterName] = sValue;
this.filters[el.filterName] = sValue;
...

################################################


applyFilters: function(bLoad)
{
if(arguments.length < 1)
bLoad = true;
for(var fn in this.filterFields)
{
this.applyFilter(this.filterFields[fn], false);
}
// CHANGE: attach all filters to one param
this.grid.store.baseParams['filters'] = this.filters;
if(bLoad)
this.storeReload();
},

################################################

This is only a dirt example, but make this feature configurable would
be a great benefit for the plugin.

It is a must have for DirectStore implementations, where Post Params
are Mapped to Remote Classes with known Constructors.
Inside Ext, also the param order is hardcoded
---
Inside Store


,directFn: Adresse.find
,paramOrder: ['start', 'limit', 'sort', 'dir', 'filters']

so any unknown param won't be seen by the remote function!

For this reason, a posted filter list via name is not possible.

Also Saki's Search Extension and some other plugs are using this technique.

Maybe Mr. Zucconi can implement this feature in a next release.

Best wishes,
Holger

taron133
14 Feb 2010, 12:11 PM
Columns width is crash if switch hide/show columns in grid. :">

If "viewConfig:{autoFill:true,forceFit:true}" - columns width is bad.
If element was hidden:true, and at some moment will be show() - filter not display.

storeReload not work, because of "this.grid.store.lastOptions" (undefined).
"this.grid.store.baseParams" needed may be.

Needed:

change: function(field, value){
if (value != field.value) this.applyFilter(field);
}for optimization

My Ext:3x

kdeelstra
15 Feb 2010, 6:49 AM
Live Demo
http://84.253.168.37:8090/w2p/docs.html

this link is not working...

ob1
17 Mar 2010, 4:30 AM
Hi,

Tested with Ext versions 3.0-3.1.1 and plugin versions 1.0.5/1.0.9.

I start up my grid with several columns hidden (by calling "ColumnModel.setHidden").
Now, when making these columns visible by using the grid header menu, the columns appear but without the filter.

Some debugging showed me that inside "onColHidden" you do "panel.doLayout();" which returns pretty early since "canLayout" returns false.

Possible solution - calling "panel.doLayout" with the "force" parameter = "true" works for me.
Not sure this is the best solution, as I didn't dig deep to really understand the problem, but thought I'd share what I have.

Thanks for the great plugin :)

yumusakg
29 Jun 2010, 11:56 PM
is there a demo page for this plugin?
this link http://84.253.168.37:8090/w2p/docs.html does not work..

ob1
4 Jul 2010, 9:17 PM
You add "getHeaderFilterField" as a function of the grid, but the named parameter "sFn" is inconsistent with the usage inside the function which refers to "fn", not "sFn".

Calling this function is guaranteed to explode ;)

yumusakg
7 Jul 2010, 9:43 PM
autoexpand column does not resize when a hidden column made visible. this needs to be fixed.

sdc53
22 Jul 2010, 4:50 PM
(http://www.sencha.com/member.php?39676-d.zucconi)[/URL]d.zucconi,
I'm having a difficult time getting your plugin to work - using GridHeaderFilters 1.09 on Ext 3.1.1. The filters do not appear under the column headers in the grid. Someone else commented on a similar problem - resolution was "filters not being set". I've verified in Firebug they are there. I've spent a day trying to figure it out and am now resorting to a lowly forum post. Any suggestions?
[URL="http://www.sencha.com/member.php?39676-d.zucconi"] (http://www.sencha.com/member.php?39676-d.zucconi)

sdc53
26 Jul 2010, 12:41 PM
I figured out the answer to my own problem - I was trying to use a BufferGridView, as soon as I switched to the default type the header row appeared.

dolittle
26 Jul 2010, 12:41 PM
When using combobox filters resetHeaderFilters doesn't clear them.
Instead, it set the value to the first item in the list.
I modified the reset function to take care of that:

this.grid.resetHeaderFilters = function(bReload)
{
if(!this.headerFilters)
return;
if(arguments.length == 0)
var bReload = true;
for(var fn in this.headerFilters.filterFields)
{
var el = this.headerFilters.filterFields[fn];
if(el.clearValue) {
el.clearValue();
} else {
this.headerFilters.setFieldValue(el, "");
}
this.headerFilters.applyFilter(el, false);
}
if(bReload)
this.headerFilters.storeReload();
};

dzj
2 Aug 2010, 12:07 AM
I have modified something:

//Pannello filtri
var filterPanelDiv = headerTd.createChild({id: Ext.id(), tag: "div"});
filterPanelDiv.setHeight(this.height);
var panelConfig = {
/*id: "filter-panel-"+colCfg.id,*/
renderTo: filterPanelDiv,
width: iPanelWidth,
height: this.height,
border: false,
//bodyStyle: "background-color: transparent; padding: 2px",
bodyStyle: "padding: " + this.padding + "px; background-color: transparent",
bodyBorder: false,
layout: "fit",
items: [],
stateful: false
};

//applyMode: auto o enter
if(this.applyMode == "auto" || this.applyMode == "change" || Ext.isEmpty(this.applyMode))
{
filterConfig.listeners =
{
change: function(field){
var t = field.getXType();
if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
return;
}else{
this.applyFilter(field);
}
},
specialkey: function(el,ev)
{
ev.stopPropagation();
if(ev.getKey() == ev.ENTER)
//el.el.dom.blur();
this.applyFilters();
},
select: function(field){this.applyFilter(field);},
scope: this
};
}

d.zucconi
5 Aug 2010, 10:50 PM
You add "getHeaderFilterField" as a function of the grid, but the named parameter "sFn" is inconsistent with the usage inside the function which refers to "fn", not "sFn".

Calling this function is guaranteed to explode ;)
Thanks for your report. The bug is now fixed in 1.0.12.

d.zucconi
5 Aug 2010, 10:52 PM
When using combobox filters resetHeaderFilters doesn't clear them.
Instead, it set the value to the first item in the list.
I modified the reset function to take care of that:

this.grid.resetHeaderFilters = function(bReload)
{
if(!this.headerFilters)
return;
if(arguments.length == 0)
var bReload = true;
for(var fn in this.headerFilters.filterFields)
{
var el = this.headerFilters.filterFields[fn];
if(el.clearValue) {
el.clearValue();
} else {
this.headerFilters.setFieldValue(el, "");
}
this.headerFilters.applyFilter(el, false);
}
if(bReload)
this.headerFilters.storeReload();
};
Thanks for your suggestion. I've updated this function in version 1.0.12 of GridHeaderFilters plugin.

d.zucconi
5 Aug 2010, 11:01 PM
I have modified something:

//Pannello filtri
var filterPanelDiv = headerTd.createChild({id: Ext.id(), tag: "div"});
filterPanelDiv.setHeight(this.height);
var panelConfig = {
/*id: "filter-panel-"+colCfg.id,*/
renderTo: filterPanelDiv,
width: iPanelWidth,
height: this.height,
border: false,
//bodyStyle: "background-color: transparent; padding: 2px",
bodyStyle: "padding: " + this.padding + "px; background-color: transparent",
bodyBorder: false,
layout: "fit",
items: [],
stateful: false
};

//applyMode: auto o enter
if(this.applyMode == "auto" || this.applyMode == "change" || Ext.isEmpty(this.applyMode))
{
filterConfig.listeners =
{
change: function(field){
var t = field.getXType();
if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
return;
}else{
this.applyFilter(field);
}
},
specialkey: function(el,ev)
{
ev.stopPropagation();
if(ev.getKey() == ev.ENTER)
//el.el.dom.blur();
this.applyFilters();
},
select: function(field){this.applyFilter(field);},
scope: this
};
}

Thanks for your suggestion: I've added the "padding config" and "change listener" updates to the latest version of plugin code. In this version I've also added the "applyFilterEvent" configuration for each filter field that allow user to select the event to listen for filter application.
However in my apps I always use applyMode = "enter": is the most appreciated by users.

ultraman69
7 Sep 2010, 10:13 AM
Hi ! This pluggin seems to be exactly what I need, but I can't make it work :-( I'm a total newbie to EXtJS so, I know the problem is on my side. Probably with my data store. Here's the code that I use :



Ext.onReady(function() {

var movieStore = new Ext.data.Store({
url: 'movies.json',
reader: new Ext.data.JsonReader({
root: 'rows',
id: 'id'
}, [
'id',
'coverthumb',
'title',
'director',
{ name: 'released', type: 'date', dateFormat: 'Y-m-d' },
'genre',
'tagline',
{ name: 'price', type: 'float' },
{ name: 'available', type: 'bool' }
])
});

movieStore.load();

var grid = new Ext.grid.GridPanel({
renderTo: document.body,
frame: true,
title: 'Movie Database',
height: 300,
width: 800,
enableColumnMove: true,
store: movieStore,
plugins: [new Ext.ux.grid.GridHeaderFilters()],
cm: new Ext.grid.ColumnModel([{
id: 'title',
header: "Titre",
width: 300,
sortable: true,
dataIndex: "title",
filter: { xtype: "textfield", filterName: "title" }
}, {
id: "director",
header: "Realisateur",
width: 200,
sortable: true,
dataIndex: "director",
filter: { xtype: "textfield" }
}, {
id: "released",
header: "Date de sorti",
width: 75,
sortable: true,
dataIndex: "released",
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
filter: { xtype: "textfield" }
}, {
id: "genre",
header: "Genre",
width: 100,
sortable: true,
dataIndex: "genre",
filter: { xtype: "textfield" }
}])
});


}); //end onReady
This sample comes from a book, but I think it's not really up to date.

The grid is displayed. But the filters don't work. When I enter som text in the second filter field and hit the enter key, the filter fields get highlighted but, the data just stays the same.

Thanks a lot for you help !

dan_b
8 Sep 2010, 3:16 AM
I can't get it to work with 3.3 Beta 2 - it renders momentarily and then on the onafterlayout event the filters are hidden.

psm1963
17 Sep 2010, 6:10 PM
Does anyone know how to set the grid filtering on the fields at runtime/initialization. I would like to use constructors to do this. Any help would be appreciated

martinrame
20 Sep 2010, 4:44 PM
d.zucconi, could you take a look at the AutoExpandColumn bug reported by yumusakg?.

scottmartin
24 Sep 2010, 8:37 AM
Ultraman .... then you _must_ know Giant Robot! .. yes, I am showing my age ...

The filter is just sending the POST params .. you have to tell your app (server side) what to do with the information.

Regards,
Scott.

kshvakov
24 Sep 2010, 12:16 PM
thanks, good plugin

I add


this.grid.on("columnmove", this.renderFilters.createDelegate(this, [false]), this);
this.grid.on("columnresize", this.onColResize, this);
this.grid.on("resize", this.renderFilters.createDelegate(this, [false]), this);
if(this.stateful)
{
this.grid.on("beforestatesave", this.saveFilters, this);
this.grid.on("beforestaterestore", this.loadFilters, this);
}


for expand or collapse action in Viewport

scottmartin
7 Oct 2010, 8:24 AM
In testing GridHeaderFilters in 3.3-rc, the filter disappears after refreshing the grid, or anytime after the initial render:
-pagingToolbar - click refresh button
-entering a value in a column filter and hit enter to invoke filter
-leave grid panel and return
-calling resetHeaderFilters(1)

It works fine using 3.2.1

Regards,
Scott.

kshvakov
11 Oct 2010, 10:19 PM
For 3.3 I use



onRender : function () {
My.Component.superclass.onRender.apply(this, arguments);
this.el.mask(this.loadMask.msg);
this.store.load({ params : {limit : pageSize} });
this.store.on('load', function() {
this.el.unmask();
this.filter.renderFilters(false)
}, this);

}

scottmartin
12 Oct 2010, 7:33 AM
While that may work, I really do not want to pollute my code to hack a bug. I guess I need to take a walk through the code when I have the time and find out why the filterpanel feels the need to hide.

Regards,
Scott.

nickelj
13 Oct 2010, 1:49 PM
Is it possible to use this plugin in combination with the ext.ux.livegrid extension?

If so...any examples?

Jim

nassaja-rus
13 Oct 2010, 2:19 PM
What about 3.3? It seems that headers in 3.3 redraws at each update of the grid. And this destroy filters with combo.

nickelj
13 Oct 2010, 3:39 PM
What about 3.3? It seems that headers in 3.3 redraws at each update of the grid. And this destroy filters with combo.

Yeah....I have tested with 3.3 and with 3.2.1....

3.2.1 works, 3.3 does not.

Jim

daddie888
13 Oct 2010, 11:40 PM
Is it possible to use this plugin in combination with the ext.ux.livegrid extension?

If so...any examples?

Jim

Nice solution, i use it with activewidgets grid and don't like to reïnvent the wheel so i'm trying to get yours to work with livegrid but it doesn't work with Ext JS v3.2.1 nor v3.3.0.
In a plain grid without livegrid i get the filterrow but nothing happens when i put a value in the filter and hit ENTER.
In livegrid the filterrow renders first but is covered by the body of the grid.
Not sure if i got everything right, the example link http://84.253.168.37:8090/w2p/docs.html you refer to doesn't work..

Thanks,
Peter

Nicolas BUI
14 Oct 2010, 4:40 AM
Hi,

In fact, as what i can see (debugging), the grid headers is rendered 2 times ?
So the first time, the plugin is well rendered as the header is here (with firebug, header TDs has id).
But few milliseconds after, the view render the header cells again (with firebug, header TDs has lost id). That's why the plugin disapear after.
So after checking the doc, I've saw the event "viewready" that make things work as expected as it's mean at least that grid has completly finish as you can select rows after that).

So, to make it render properly with Ext 3.3.0, you have to use the event "viewready" instead of "render" as a workaround ?




.....
applyFiltersText: "Apply filters",

init:function(grid)
{
this.grid = grid;
this.gridView = null;
this.panels = [];
//I TD corrispondenti ai vari headers
this.headerCells = null;
this.grid.on("viewready", this.onRender, this);
this.grid.on("columnmove", this.renderFilters.createDelegate(this, [false]), this);
this.grid.on("columnresize", this.onColResize, this);


Edit (15h56): It's seem that using "viewready" is not enough too as is the grid refresh again, the rendering will be lost. So, instead using "viewready", It seem to work better with view "refresh" event .... :


this.grid.getView().on("refresh", this.onRender, this);

Good luck !

ttbgwt
14 Oct 2010, 8:15 AM
So where did you put?


this.grid.getView().on("refresh", this.onRender, this);

nickelj
14 Oct 2010, 5:08 PM
Is it possible to use this plugin in combination with the ext.ux.livegrid extension?

If so...any examples?

Jim

scottmartin
15 Oct 2010, 5:01 AM
The fix presented by Nicolas caused many redraw issues and I had to force quit FF.

-The initial screen showed all field.
-Entering a filter value only shows editors in filter panel up to that field. All others were missing.
-Missing editors in panel flashed repeatedly and eventually crashed browser.

Please present your entire snippet of changed code if you feel this is incorrect.

Regards,
Scott.

Nicolas BUI
18 Oct 2010, 12:17 AM
@scottmartin : you are right, in come case, my fix won't work as you can ends with infinite loop...

Actually the filter render directly in the header cell ... that's not a good idea becase it cause many problems with refreshing data and mess with css. Instead it should create a second row and render on it.

justin.lucas
18 Oct 2010, 7:06 AM
anyone know what ever happened to this functionality?:

* If set to "button" an apply button is rendered near each filter. When user push this button all filters are applied at the same time. This
* could be useful if you want to set more than one filter before reload the store.

that is what i need most! i appreciate any advise/help.

thank you!

imran
18 Oct 2010, 11:52 AM
Anyone managed to get this working with the Ext.ux.grid.LockingGridView/Ext.ux.grid.LockingColumnModel UX bundled in 3.2.1?

jorgelive
22 Oct 2010, 2:26 PM
Hi,



this.grid.getView().on("refresh", this.onRender, this);

In my case causes reloading store forever!!

Better:


this.grid.getView().on("refresh", this.onRefresh, this);

dougbieber
28 Oct 2010, 8:42 AM
Although I'm not using the filter grid I did create my own by placing some combo boxes in the header element of the columns. This worked fine for 3.2.2. However, when the refresh is performed the headers are overwritten. I did find this difference in the code between 3.2.2 and 3.3:

In 3.3, the onDataChange event in GridView calls refresh with a parameter of "true" indicating to refresh the headers. In 3.2.2 there is no such parameter passed. On constructing my GridView I override onDataChange and call the refresh w/out any parameter. The headers stay intact although I found another bug.

dolittle
2 Nov 2010, 8:12 AM
Is it possible to have more than one field in a column header?
For example from/to filters or date range.

It'll make this plugin ten times more powerful.
Extjs support for grid filters is very confusing to users.

Please see the attached image.

qooleot
7 Nov 2010, 6:04 AM
dolittle - that isn't supported I believe. I modified the source to have a combobox (contains, contains exactly, starts with, ends with, does not contain) and a textfield (for actually searching) in the same column - so its definitely possible though. The trick was to modify the createFilterPanel function in the source by building up an array of widgets (combobox, textfield, etc.), adding listeners to each one, then rendering them in the panel in the header:



panelConfig.items.push(textSearchTypeComboConfig);
panelConfig.items.push(filterConfig);

filterPanel = new Ext.Panel(panelConfig);
filterPanel.render(headerTd);
var filterField = filterPanel.items.items[1];
this.filterFields[filterName] = filterField;

d.zucconi
8 Nov 2010, 12:04 PM
Hi all,

I've recently finished to rewrite the plugin code, and I've tested it only with ExtJS 3.3.0.
The new version (2.0.2b) contains new rendering code for filters and columns headers (fixing also rendering problems with new Ext 3.3.0 GridView behaviour).
This version also supports more than one filter for each column: filters are rendered into panels with FormLayout, so you can specify labels for filter fields or others specific attributes.
I've alse changed header highlight behaviour: now the highlight applies a CSS class or a background color to the grid header <tr> element (no more applied to each filter container).

Here is the code:


Ext.namespace("Ext.ux.grid");

/**
* @class Ext.ux.grid.GridHeaderFilters
* @extends Ext.util.Observable
*
* Plugin that enables filters in columns headers.
*
* To add a grid header filter, put the "filter" attribute in column configuration of the grid column model.
* This attribute is the configuration of the Ext.form.Field to use as filter in the header or an array of fields configurations.<br>
* <br>
* The filter configuration object can include some special attributes to manage filter configuration:
* <ul>
* <li><code>filterName</code>: to specify the name of the filter and the corresponding HTTP parameter used to send filter value to server.
* If not specified column "dataIndex" attribute will be used, if more than one filter is configured for the same column, the filterName will be the "dataIndex" followed by filter index (if index &gt; 0)</li>
* <li><code>value</code>: to specify default value for filter. If no value is provided for filter (in <code>filters</code> plugin configuration parameter or from loaded status),
* this value will be used as default filter value</li>
* <li><code>filterEncoder</code>: a function used to convert filter value returned by filter field "getValue" method to a string. Useful if the filter field getValue() method
* returns an object that is not a string</li>
* <li><code>filterDecoder</code>: a function used to convert a string to a valid filter field value. Useful if the filter field setValue(obj) method
* needs an object that is not a string</li>
* <li><code>applyFilterEvent</code></li>: a string that specifies the event that starts filter application for this filter field. If not specified, the "applyMode" is used. (since 1.0.10)</li>
* </ul>
* <br>
* Filter fields are rendered in the header cells within an <code>Ext.Panel</code> with <code>layout='form'</code>.<br>
* For each filter you can specify <code>fieldLabel</code> or other values supported by this layout type.<br>
* You can also override panel configuration using <code>containerConfig</code> attribute.<br>
* <br>
* This plugin enables some new grid methods:
* <ul>
* <li>getHeaderFilter(name)</li>
* <li>getHeaderFilterField(name)</li>
* <li>setHeaderFilter(name, value)</li>
* <li>setHeaderFilters(object, [bReset], [bReload])</li>
* <li>resetHeaderFilters([bReload])</li>
* <li>applyHeaderFilters([bReload])</li>
* </ul>
* The "name" is the filterName (see filterName in each filter configuration)
*
* @author Damiano Zucconi - http://www.isipc.it
* @version 2.0.2b - 17/11/2010
*/
Ext.ux.grid.GridHeaderFilters = function(cfg){if(cfg) Ext.apply(this, cfg);};

Ext.extend(Ext.ux.grid.GridHeaderFilters, Ext.util.Observable,
{
/**
* @cfg {Number} fieldHeight
* Height for each filter field used by <code>autoHeight</code>.
*/
fieldHeight: 22,

/**
* @cfg {Number} padding
* Padding for filter fields. Default: 2
*/
fieldPadding: 1,

/**
* @cfg {Boolean} highlightOnFilter
* Enable grid header highlight if active filters
*/
highlightOnFilter: true,

/**
* @cfg {String} highlightColor
* Color for highlighted grid header
*/
highlightColor: 'yellow',

/**
* @cfg {String} highlightCls
* Class to apply to filter header when filters are highlighted. If specified overrides highlightColor.
* See <code>highlightOnFilter</code>.
*/
highlightCls: null,

/**
* @cfg {Boolean} stateful
* Enable or disable filters save and restore through enabled Ext.state.Provider
*/
stateful: true,

/**
* @cfg {String} applyMode
* Sets how filters are applied. If equals to "auto" (default) the filter is applyed when filter field value changes (change, select, ENTER).
* If set to "enter" the filters are applied only when user push "ENTER" on filter field.<br>
* See also <code>applyFilterEvent</code> in columnmodel filter configuration: if this option is specified in
* filter configuration, <code>applyMode</code> value will be ignored and filter will be applied on specified event.
* @since Ext.ux.grid.GridHeaderFilters 1.0.6
*/
applyMode: "auto",

/**
* @cfg {Object} filters
* Initial values for filters (mapped with filters names). If this object is defined,
* its attributes values overrides the corresponding filter values loaded from grid status or <code>value</code> specified in column model filter configuration.<br>
* Values specified into column model configuration (filter <code>value</code> attribute) are ignored if this object is specified.<br>
* See <code>filtersInitMode</code> to understand how these values are mixed with values loaded from grid status.
* @since Ext.ux.grid.GridHeaderFilters 1.0.9
*/
filters: null,

/**
* @cfg {String} filtersInitMode
* If <code>filters</code> config value is specified, this parameter defines how these values are used:
* <ul>
* <li><code>replace</code>: these values replace all values loaded from grid status (status is completely ignored)</li>
* <li><code>merge</code>: these values overrides values loaded from status with the same name. Other status values are keeped and used to init filters.</li>
* </ul>
* This parameter doesn't affect how filter <code>value</code> attribute is managed: it will be always ignored if <code>filters</code> object is specified.<br>
* Default = 'replace'
*/
filtersInitMode: 'replace',

/**
* @cfg {Boolean} ensureFilteredVisible
* If true, forces hidden columns to be made visible if relative filter is set. Default = true.
*/
ensureFilteredVisible: true,

cfgFilterInit: false,

/**
* @cfg {Object} containerConfig
* Base configuration for filters container of each column. With this attribute you can override filters container panel configuration.
*/
containerConfig: null,

fcc: null,

filterFields: null,

filterContainers: null,

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

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

var gv = this.grid.getView();
gv.updateHeaders = gv.updateHeaders.createSequence(function(){
this.renderFilters.call(this);
},this).createInterceptor(function(){
this.destroyFilters.call(this);
return true;
},this);
this.grid.on({
scope: this,
render: this.onRender,
resize: this.onResize,
columnresize: this.onColResize,
beforedestroy: this.destroyFilters
});
//this.grid.on("columnmove", this.renderFilters, this);
if(this.stateful)
{
this.grid.on("beforestatesave", this.saveFilters, this);
this.grid.on("beforestaterestore", this.loadFilters, this);
if(this.filters)
{
//this.grid.on('afterrender', function(grid){grid.fireEvent('filterinit',this.filters);},this,{single: true});
}
}

this.grid.getColumnModel().on("hiddenchange", this.onColHidden, this);

this.grid.addEvents(
/**
* @event filterupdate
* <b>Event enabled on the GridPanel</b>: fired when a filter is updated
* @param {String} name Filter name
* @param {Object} value Filter value
* @param {Ext.form.Field} el Filter field
*/
'filterupdate',
/**
* @event filterinit
* <b>Event enabled on the GridPanel</b>: fired when the <code>filters</code> configuration
* parameter is present and the grid has been rendered. Useful to fire filters stateful events
* on grid initialization.
* @param {Object} filters Current filters values
*/
'filterinit');

this.addEvents(
/**
* @event render
* Fired when filters render on grid header is completed
* @param {Ext.ux.grid.GridHeaderFilters} this
*/
{'render': true}
);

//Must ignore filter config value ?
this.cfgFilterInit = Ext.isDefined(this.filters) && this.filters !== null;
if(!this.filters)
this.filters = {};

/*Filters config*/
var filteredColumns = this.grid.getColumnModel().getColumnsBy(function(cc){
if(Ext.isObject(cc.filter) || Ext.isArray(cc.filter))
return true;
else
return false;
});

/*Building filters containers configs*/
this.fcc = {};
for (var i = 0; i < filteredColumns.length; i++)
{
var co = filteredColumns[i];
var fca = co.filter;
if(!Ext.isArray(fca))
fca = [fca];
for(var ci = 0; ci < fca.length; ci++)
{
var fc = Ext.apply({
filterName: ci > 0 ? co.dataIndex+ci : co.dataIndex
},fca[ci]);
Ext.apply(fc, {
columnId: co.id,
dataIndex: co.dataIndex,
hideLabel: Ext.isEmpty(fc.fieldLabel),
anchor: '100%'
})

if(!this.cfgFilterInit && !Ext.isEmpty(fc.value))
{
this.filters[fc.filterName] = Ext.isFunction(fc.filterEncoder) ? fc.filterEncoder.call(this, fc.value) : fc.value;
}
delete fc.value;

/*
* Se la configurazione del field di filtro specifica l'attributo applyFilterEvent, il filtro verrà applicato
* in corrispondenza di quest'evento specifico
*/
if(fc.applyFilterEvent)
{
fc.listeners = {scope: this};
fc.listeners[fc.applyFilterEvent] = function(field){this.applyFilter(field);};
delete fc.applyFilterEvent;
}
else
{
//applyMode: auto o enter
if(this.applyMode === 'auto' || this.applyMode === 'change' || Ext.isEmpty(this.applyMode))
{
//Legacy mode and deprecated. Use applyMode = "enter" or applyFilterEvent
fc.listeners =
{
change: function(field)
{
var t = field.getXType();
if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
return;
}else{
this.applyFilter(field);
}
},
specialkey: function(el,ev)
{
ev.stopPropagation();
if(ev.getKey() == ev.ENTER)
el.el.dom.blur();
},
select: function(field){this.applyFilter(field);},
scope: this
};
}
else if(this.applyMode === 'enter')
{
fc.listeners =
{
specialkey: function(el,ev)
{
ev.stopPropagation();
if(ev.getKey() == ev.ENTER)
{
this.applyFilters();
}
},
scope: this
};
}
}

//Looking for filter column index
var containerCfg = this.fcc[fc.columnId];
if(!containerCfg)
{
containerCfg = {
cls: this.filterContainerCls,
border: false,
bodyBorder: false,
/*layout: 'vbox',
layoutConfig: {align: 'stretch', padding: this.padding},*/
labelSeparator: '',
labelWidth: 50,
layout: 'form',
style: {},
items: []
};
if(this.containerConfig)
Ext.apply(containerCfg, this.containerConfig);
this.fcc[fc.columnId] = containerCfg;
}
containerCfg.items.push(fc);
}
}

Ext.ux.grid.GridHeaderFilters.superclass.constructor.call(this);

if(this.stateful)
{
if(!Ext.isArray(this.grid.stateEvents))
this.grid.stateEvents = [];
this.grid.stateEvents.push('filterupdate');
this.grid.stateEvents.push('filterinit');
}

//Enable new grid methods
Ext.apply(this.grid, {
headerFilters: this,
getHeaderFilter: function(sName){
if(!this.headerFilters)
return null;
return this.headerFilters.filters[sName];
},
setHeaderFilter: function(sName, sValue){
if(!this.headerFilters)
return;
var fd = {};
fd[sName] = sValue;
this.setHeaderFilters(fd);
},
setHeaderFilters: function(obj, bReset, bReload)
{
if(!this.headerFilters)
return;
if(bReset)
this.resetHeaderFilters(false);
if(arguments.length < 3)
var bReload = true;
var bOne = false;
for(var fn in obj)
{
if(this.headerFilters.filterFields[fn])
{
var el = this.headerFilters.filterFields[fn];
this.headerFilters.setFieldValue(el,obj[fn]);
this.headerFilters.applyFilter(el, false);
bOne = true;
}
}
if(bOne && bReload)
this.headerFilters.storeReload();
},
getHeaderFilterField: function(fn)
{
if(!this.headerFilters)
return;
if(this.headerFilters.filterFields[fn])
return this.headerFilters.filterFields[fn];
else
return null;
},
resetHeaderFilters: function(bReload)
{
if(!this.headerFilters)
return;
if(arguments.length == 0)
var bReload = true;
for(var fn in this.headerFilters.filterFields)
{
var el = this.headerFilters.filterFields[fn];
if(Ext.isFunction(el.clearValue))
{
el.clearValue();
}
else
{
this.headerFilters.setFieldValue(el, '');
}
this.headerFilters.applyFilter(el, false);
}
if(bReload)
this.headerFilters.storeReload();
},
applyHeaderFilters: function(bReload)
{
if(arguments.length == 0)
var bReload = true;
this.headerFilters.applyFilters(bReload);
}
});

},

renderFilterContainer: function(columnId, fcc)
{
if(!this.filterContainers)
this.filterContainers = {};
//Associated column index
var ci = this.grid.getColumnModel().getIndexById(columnId);
//Header TD
var td = this.grid.getView().getHeaderCell(ci);
td = Ext.get(td);
//Patch for field text selection on Mozilla
if(Ext.isGecko)
td.dom.style.MozUserSelect = "text";
td.dom.style.verticalAlign = 'top';
//Render filter container
fcc.width = td.getWidth() - 3;
var fc = new Ext.Container(fcc);
fc.render(td);
//Container cache
this.filterContainers[columnId] = fc;
//Fields cache
var height = 0;
if(!this.filterFields)
this.filterFields = {};
var fields = fc.findBy(function(cmp){return !Ext.isEmpty(cmp.filterName)});
if(!Ext.isEmpty(fields))
{
for(var i=0;i<fields.length;i++)
{
var filterName = fields[i].filterName;
/*if(this.filterFields[filterName])
{
//Ext.destroy(this.filterFields[filterName])
delete this.filterFields[filterName];
}*/
this.filterFields[filterName] = fields[i];
height += fields[i].getHeight();
}
}

return fc;
},

renderFilters: function()
{
for(var cid in this.fcc)
{
this.renderFilterContainer(cid, this.fcc[cid]);
}
this.setFilters(this.filters);
this.highlightFilters(this.isFiltered());
},

onRender: function()
{
this.renderFilters();
if(this.isFiltered())
{
this.applyFilters(false);
}
this.fireEvent("render", this);
},

getFilterField: function(filterName)
{
return this.filterFields ? this.filterFields[filterName] : null;
},

/**
* Sets filter values by values specified into fo.
* @param {Object} fo Object with attributes filterName = value
* @param {Boolean} clear If current values must be cleared. Default = false
*/
setFilters: function(fo,clear)
{
this.filters = fo;

if(this.filters && this.filterFields)
{
for(var fn in this.filterFields)
{
var field = this.filterFields[fn];
var value = this.filters[field.filterName];
if(Ext.isEmpty(value))
{
if(clear)
this.setFieldValue(field, '');
}
else
this.setFieldValue(field, value);
}
}
},

onColResize: function(index, iWidth){
var colId = this.grid.getColumnModel().getColumnId(index);
var cnt = this.filterContainers[colId];
if(cnt)
{
if(isNaN(iWidth))
iWidth = 0;
var filterW = (iWidth < 3) ? 0 : (iWidth - 3);
cnt.setWidth(filterW);
//Thanks to ob1
cnt.doLayout(false,true);
}
},

/**
* @private
* Resize filters containers on grid resize
* Thanks to dolittle
*/
onResize: function()
{
var n = this.grid.getColumnModel().getColumnCount();
for(var i=0; i<n; i++) {
var td = this.grid.getView().getHeaderCell(i);
td = Ext.get(td);
this.onColResize(i, td.getWidth());
}
},

onColHidden: function(cm, index, bHidden){
if(bHidden)
return;
var cw = this.grid.getColumnModel().getColumnWidth(index);
this.onColResize(index, cw);
},

saveFilters: function(grid, status)
{
var vals = {};
for(var name in this.filters)
{
vals[name] = this.filters[name];
}
status["gridHeaderFilters"] = vals;
return true;
},

loadFilters: function(grid, status)
{
var vals = status.gridHeaderFilters;
if(vals)
{
if(this.cfgFilterInit)
{
if(this.filtersInitMode === 'merge')
Ext.apply(vals,this.filters);
}
else
this.filters = vals;
}
},

isFiltered: function()
{
for(var k in this.filters)
{
if(/*this.filterFields && this.filterFields[k] && */!Ext.isEmpty(this.filters[k]))
return true;
}
return false;
},

highlightFilters: function(enable)
{
if(!this.highlightOnFilter)
return;
if(!this.filterContainers)
return;
if(!this.grid.getView().mainHd)
return;

var tr = this.grid.getView().mainHd.child('.x-grid3-hd-row');
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
tr.addClass(this.highlightCls);
else
tr.removeClass(this.highlightCls);
}
else
{
tr.setStyle('background-color',enable ? this.highlightColor : '');
}
/*for(var i=0; i < this.grid.getColumnModel().getColumnCount(); i++)
{
var hc = Ext.get(this.grid.getView().getHeaderCell(i));
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
hc.addClass(this.highlightCls);
else
hc.removeClass(this.highlightCls);
}
else
{
hc.setStyle('background-color',enable ? this.highlightColor : 'transparent');
}
}*/
/*var color = enable ? this.highlightColor : 'transparent';
for(var fn in this.filterContainers)
{
var fc = this.filterContainers[fn];
if(fc.rendered)
{
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
fc.getEl().addClass(this.highlightCls);
else
fc.getEl().removeClass(this.highlightCls);
}
else
fc.getEl().setStyle('backgroundColor',color);
}
}*/
},

getFieldValue: function(eField)
{
if(Ext.isFunction(eField.filterEncoder))
return eField.filterEncoder.call(eField, eField.getValue());
else
return eField.getValue();
},

setFieldValue: function(eField, value)
{
if(Ext.isFunction(eField.filterDecoder))
value = eField.filterDecoder.call(eField, value);
eField.setValue(value);
},

applyFilter: function(el, bLoad)
{
if(arguments.length < 2)
bLoad = true;
if(!el)
return;

if(!el.isValid())
return;

var sValue = this.getFieldValue(el);


if(Ext.isEmpty(sValue))
{
delete this.grid.store.baseParams[el.filterName];
delete this.filters[el.filterName];
}
else
{
this.grid.store.baseParams[el.filterName] = sValue;
this.filters[el.filterName] = sValue;

if(this.ensureFilteredVisible)
{
//Controllo che la colonna del filtro applicato sia visibile
var ci = this.grid.getColumnModel().getIndexById(el.columnId);
if((ci >= 0) && (this.grid.getColumnModel().isHidden(ci)))
this.grid.getColumnModel().setHidden(ci, false);
}
}

//Evidenza filtri se almeno uno attivo
this.highlightFilters(this.isFiltered());

this.grid.fireEvent("filterupdate",el.filterName,sValue,el);

if(bLoad)
this.storeReload();
},

applyFilters: function(bLoad)
{
if(arguments.length < 1)
bLoad = true;
for(var fn in this.filterFields)
{
this.applyFilter(this.filterFields[fn], false);
}
if(bLoad)
this.storeReload();
},

storeReload: function()
{
if(!this.grid.store.lastOptions)
return;
var slp = {start: 0};
if(this.grid.store.lastOptions.params && this.grid.store.lastOptions.params.limit)
slp.limit = this.grid.store.lastOptions.params.limit;
this.grid.store.load({params: slp});
},

getFilterContainer: function(columnId)
{
return this.filterContainers ? this.filterContainers[columnId] : null;
},

destroyFilters: function()
{
if(this.filterFields)
{
for(var ff in this.filterFields)
{
Ext.destroy(this.filterFields[ff])
delete this.filterFields[ff];
}
}

if(this.filterContainer)
{
for(var ff in this.filterContainers)
{
Ext.destroy(this.filterContainers[ff])
delete this.filterContainers[ff];
}
}

}
});


I'm testing this new version with ExtJS 3.3.0. Not yet with 3.2.3 nor 3.2.2.
Please report any problem or suggestion.

Thanks :)

scottmartin
8 Nov 2010, 3:08 PM
Downloaded v2-Beta and replaced existing GHF code. Initial grid render does not display the editors ... only the panel space where the editors would exists. Clicking any of the column headers will cause the filter editors to render and all is fine.

Same result on FF 3.6.12 and Chromium: 9.0.576.0

Regards,
Scott.

scottmartin
8 Nov 2010, 3:15 PM
FYI,
Adding:


this.grid.on("resize", this.renderFilters.createDelegate(this, [false]), this);

Fixes my initial draw problem.

I also include:



this.grid.on("reconfigure", this.renderFilters.createDelegate(this, [false]), this);



Regards,
Scott.

LisburnLad
8 Nov 2010, 3:19 PM
Hi - I just tried your latest plugin (V2 Beta), after updating my ExtJS to 3.3.
Unfortunately I'm getting a crash in the 'renderFilterContainer' function, on the line 'Ext.destroy(ofc);'

I only have a single filter (the same as the one in your example) and the ID of this column is correctly passed through to the function, so I'm not sure what's gone wrong.

If you need any further info let me know.

[Update] - I'm getting this problem in IE8 - I just tried Firefox 3.5.15, and it seems to be fine

Regards,
Steve

d.zucconi
9 Nov 2010, 12:05 AM
Downloaded v2-Beta and replaced existing GHF code. Initial grid render does not display the editors ... only the panel space where the editors would exists. Clicking any of the column headers will cause the filter editors to render and all is fine.
Hi, thanks for your hints.
Today I've tested the plugin with FF 3.6.12, Chrome 7.0.517.44 and IE8. I've found some bugs (and updated my last post (http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=536346#post536346)) but I can't reproduce your problem.
Could you please post code example ?
What is your version of ExtJS ? 3.3.0 ?

Bye

d.zucconi
9 Nov 2010, 12:10 AM
Hi - I just tried your latest plugin (V2 Beta), after updating my ExtJS to 3.3.
Unfortunately I'm getting a crash in the 'renderFilterContainer' function, on the line 'Ext.destroy(ofc);'

I only have a single filter (the same as the one in your example) and the ID of this column is correctly passed through to the function, so I'm not sure what's gone wrong.

If you need any further info let me know.

[Update] - I'm getting this problem in IE8 - I just tried Firefox 3.5.15, and it seems to be fine

Regards,
Steve
Hi Steve,

I've chanded plugin destroy logic (that was incompatible with IE) and updated my last post (http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=536346#post536346) with the new code.
IE problem seems to be fixed.

Thanks for your help

LisburnLad
9 Nov 2010, 12:11 PM
Hi Steve,

I've chanded plugin destroy logic (that was incompatible with IE) and updated my last post (http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=536346#post536346) with the new code.
IE problem seems to be fixed.

Thanks for your help

Hi - just to let you know that your change has fixed it for me as well on IE.
Ta,
Steve

kshvakov
9 Nov 2010, 12:43 PM
resizing the grid does not change the size of the filter. For example collapse west panel in border layout (grid width filter is center region)

ExtJS 3.3, all browsers

PS : no grid.on('resize', ..) action

webtime
9 Nov 2010, 2:18 PM
Hello all!!!
I've a dynamic grid (json configuired) created as follow:


xgrid = new Ext.ux.GridExtension({
border:false
,stateful:false
,store:store
,loadMask: true
,stripeRows: true
,plugins: [new Ext.ux.grid.GridHeaderFilters()]
,columns:[]
,viewConfig:{onDataChange: function(){
var columns = [];
columns.push(smodel);
for (var i = 0; i < this.ds.reader.jsonData.totcol; i++) {
eval("this.ds.reader.jsonData.columns[i].renderer = "+this.ds.reader.jsonData.columns[i].renderer);
columns.push(this.ds.reader.jsonData.columns[i]);
}
this.cm.setConfig(columns);
this.syncFocusEl(0);

},
forceFit:true,
emptyText: 'No records.'}
,tbar: tb
,sm : smodel
,bbar : new Ext.PagingToolbar({
store: store
,displayInfo:true
,pageSize:Prowperpage
})
});... and this is my json..


{"metaData":
{"totalProperty": "total",
"root": "records",
"fields": [{"name":"objectUser","mapping":"Utilizzatore","type":"string"},
{"name":"objectCode","mapping":"Oggetto","type":"string"},
{"name":"userID","mapping":"Utente\/*all","type":"string"},
{"name":"applicationArea","mapping":"Area Applicativa","type":"string"},
{"name":"mKey","mapping":"mKey","type":"string"}
]},
"success": true,
"total": 164,
"records": [-------],
"totcol":4,
"columns": [
{"dataIndex":"objectUser","header":"Utilizzatore","filter":{"xtype":"textfield"},"decorated":false},
{"dataIndex":"objectCode","header":"Oggetto","filter":{"xtype":"textfield"},"decorated":false},
{"dataIndex":"userID","header":"Utente\/*all","filter":{"xtype":"textfield"},"decorated":false},
{"dataIndex":"applicationArea","header":"Area Applicativa","filter":{"xtype":"textfield"},"decorated":false},
{"dataIndex":"mKey","header":"mKey","hidden":true}]}... but i don't see any filter in grid... without errors...
Anyone can help?? Please..

I've using EXT 3.3.0
Thanks

EDIT..
In firebug i see that:
When the plugin is inizialized, the column model does not exist yet. This is due to the type of column model (loaded via json)???

scottmartin
10 Nov 2010, 5:33 AM
@zucconi:

The code is rather basic:




var cmEmployee = new Ext.grid.ColumnModel({
columns: [
{
header: 'Last Name',
dataIndex: 'last_name',
filter: {
xtype: 'textfield',
filterName: 'cfilter_last_name'
},
renderer: is_inactive
},
{
header: 'First Name',
dataIndex: 'first_name',
filter: {
xtype: 'textfield',
filterName: 'cfilter_first_name'
}
},
{
header: 'Middle',
dataIndex: 'middle_name',
filter: {
xtype: 'textfield',
filterName: 'cfilter_middle_name'
},
width: 75
},
{
header: 'Hired',
dataIndex: 'date_hired',
xtype: 'datecolumn',
filter: {
xtype: 'datefield',
filterName: 'cfilter_date_hired'
}
},
{
header: 'Position',
dataIndex: 'position_name',
filter: {
xtype: 'textfield',
filterName: 'cfilter_position_name'
}
},
{
header: 'Captain Exp',
dataIndex: 'date_captain_expires',
filter: {
xtype: 'datefield',
filterName: 'cfilter_date_captain_expires'
},
renderer: date_pastdue
},
{
header: 'Capt Notify',
dataIndex: 'date_captain_notify',
filter: {
xtype: 'datefield',
filterName: 'cfilter_date_captain_notify'
},
renderer: date_pastdue
},
{
header: 'MMC Exp',
dataIndex: 'date_uscgmmc_expires',
filter: {
xtype: 'datefield',
filterName: 'cfilter_date_tankermans_expires'
},
renderer: date_pastdue
},
{
header: 'Radar Notify',
dataIndex: 'date_radar_notify',
filter: {
xtype: 'datefield',
filterName: 'cfilter_date_radar_notify'
},
renderer: date_pastdue
},
// joined field from employee_model.php
{
header: 'Status',
dataIndex: 'status_name',
filter: {
// column search employee status combo
xtype: 'combo',
mode: 'local',
store: storeEmployeeStatus,
triggerAction: 'all',
displayField: 'status_name',
valueField: 'status_name',
editable: true,
lazyRender: true,
filterName: 'cfilter_status_name'
},
renderer: is_inactive
},
{
header: 'City',
dataIndex: 'city',
filter: {
xtype: 'textfield',
filterName: 'cfilter_city'
},
width: 115
},
{
header: 'State',
dataIndex: 'state',
filter: {
xtype: 'textfield',
filterName: 'cfilter_state'
},
width: 50
},
// { header: 'Zip', dataIndex: 'zip', filter: {xtype: 'textfield', filterName: 'cfilter_zip'}, width: 75 },
{
header: 'Citizen',
dataIndex: 'is_us_citizen',
filter: {
// column search employee status combo
xtype: 'combo',
mode: 'local',
store: storeYN,
triggerAction: 'all',
displayField: 'answer',
valueField: 'id',
editable: true,
lazyRender: true,
filterName: 'cfilter_is_us_citizen'
},
width: 75
}
],
defaults: {
sortable: true
}
});




grid:




BMS.grid.employee_grid_panel = Ext.extend(Ext.grid.GridPanel, {
border: true,
stripeRows: true,
initComponent: function(){
this.store = storeEmployees;
this.colModel = cmEmployee;
this.selModel = new Ext.grid.RowSelectionModel({
singleSelect: true
});
this.view = new Ext.grid.GridView();

this.bbar = new Ext.PagingToolbar({
store: storeEmployees,
// grid and PagingToolbar using same store
displayInfo: true,
pageSize: browsePageSize,
plugins: new Ext.ux.SlidingPager()
});
BMS.grid.employee_grid_panel.superclass.initComponent.call(this);
this.on({
afterlayout: {
scope: this,
single: true,
fn: function(){
this.store.load({
params: {
start: 0,
limit: browsePageSize,
sort: 'last_name',
dir: 'ASC'
}
});
}
}
});
},

tbar: {}, // for search and any other buttons
plugins: [

new Ext.ux.grid.GridHeaderFilters({
applyMode: 'enter',
highlightColor: 'orange'
})

],
listeners: {
viewReady: function(){
..
}
}
});



Regards,
Scott.

d.zucconi
11 Nov 2010, 11:53 AM
Hello all!!!
In firebug i see that:
When the plugin is inizialized, the column model does not exist yet. This is due to the type of column model (loaded via json)???
This version of GridHeaderFilters configures filters panels for every column at init time (to decrease render time). So it needs an existing column model when the plugin is initialized. At this moment the plugin doesn't support column model re-configuration after grid initialization.

webtime
12 Nov 2010, 5:20 AM
This version of GridHeaderFilters configures filters panels for every column at init time (to decrease render time). So it needs an existing column model when the plugin is initialized. At this moment the plugin doesn't support column model re-configuration after grid initialization.

Thank You so much.. (Grazie!!!!)

dolittle
16 Nov 2010, 3:29 PM
I'm using the beta 2.0 version (http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=536346#post536346) with Ext 3.3.0.
I've added two things

1. It's probably better to use containers instead of panels for the filters because they are lightweight
and there is no use for the panel UI or functionality:


renderFilterContainer: function(columnId, fcc)
{
...
...
//var fc = new Ext.Panel(fcc);
var fc = new Ext.Container(fcc);
...
...
},

highlightFilters: function(enable)
{
...
...
{
var fc = this.filterContainers[fn];
if(fc.rendered)
{
if(!Ext.isEmpty(this.highlightCls))
{
if(enable)
fc.getEl().addClass(this.highlightCls);
else
fc.getEl().removeClass(this.highlightCls);
}
else
//fc.body.dom.style.backgroundColor = color;
fc.getEl().dom.style.backgroundColor = color;
}
}
}


2. I'm using a grid with a card layout so the grid is rendered hidden.
The filters are rendered with width=0 because of the line:

fcc.width = td.getWidth() - 3;
To solve this I implemented onResize method:

init:function(grid)
{
...
...
this.grid.on({
scope: this,
render: this.onRender,
resize: this.onResize,
columnresize: this.onColResize,
beforedestroy: this.destroyFilters
});
...
...
},

onResize: function()
{
var n = this.grid.getColumnModel().getColumnCount();
for(var i=0; i<n; i++) {
var td = this.grid.getView().getHeaderCell(i);
td = Ext.get(td);
this.onColResize(i, td.getWidth());
}
}


Thanks

d.zucconi
17 Nov 2010, 12:14 AM
1. It's probably better to use containers instead of panels for the filters because they are lightweight
and there is no use for the panel UI or functionality

I agree. Initially I've started developing plugin with containers instead of panels but with other layouts (such as FitLayout) I've found some problems with filter fields focus (no focus clicking on fields inserted into containers with FitLayout). Now using FormLayout there are no problems and so we can return to containers.
Thanks.



2. I'm using a grid with a card layout so the grid is rendered hidden.
The filters are rendered with width=0 because of the line:

fcc.width = td.getWidth() - 3;
To solve this I implemented onResize method

Good. It should also solve other problems.

I will update the code posted here (http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=536346#post536346) with your suggestions and other changes (new filter containers sizing and filter highlight that works directly on grid header <tr> element).

Thanks for your help dolittle

dolittle
19 Nov 2010, 10:25 AM
Thank you for adding my changes.

In my case I need to disable some of the filters when a specific filter is chosen for one of the columns.
The following code make the plugin aware of disabled fields:

applyFilter: function(el, bLoad)
{
...
if(el.disabled || Ext.isEmpty(sValue))
{
delete this.grid.store.baseParams[el.filterName];
delete this.filters[el.filterName];
}
else
...
},

qwikso
14 Dec 2010, 6:02 AM
Hi d.zucconi,

it's really great to see the new release for Ext 3.3 because of more problems with the older version. I am using your filter plugin for all my grids and the "reconfigure" function is for my application really critical. Unfortunately I'm not able to repair this code to support it. Please are you planning to finish it or can you get me an advice how to do it? I need to reconfigure column model and the header filter is not visible.

Big thanks...
qwikso

stevwinata
15 Dec 2010, 10:27 PM
hy d.zucconi......this plugin is work in Ext 3.3, i'm using your latest code for Ext 3.3 in previous page..thanks a lot for it.now,
The grid is displayed. But the filters don't work. When I enter some text in the any filter field and hit the enter key, the filter fields get highlighted but, the data just stays the same....any suggest for my datastore??firebug is ok..

d.zucconi
15 Dec 2010, 11:21 PM
Hi d.zucconi,

it's really great to see the new release for Ext 3.3 because of more problems with the older version. I am using your filter plugin for all my grids and the "reconfigure" function is for my application really critical. Unfortunately I'm not able to repair this code to support it. Please are you planning to finish it or can you get me an advice how to do it? I need to reconfigure column model and the header filter is not visible.

The current beta doesn't support grid reconfiguration.
At this moment I don't have much time for plugin development... maybe at the end of this month.
Unfortunately I don't use grid reconfiguration in my apps, so the plugin wasn't engineered to support it...

d.zucconi
15 Dec 2010, 11:26 PM
the filters don't work. When I enter some text in the any filter field and hit the enter key, the filter fields get highlighted but, the data just stays the same....any suggest for my datastore??firebug is ok..
It's hard to say what is the cause of your problem without an example of your code...

rubaiz
28 Dec 2010, 11:56 AM
Still no demo page?

sajidalimudassar
10 Jan 2011, 4:25 AM
Hello, I am using ExtJs 3.3.1.
I have updated my GridHeaderFilters to 2.0.2b. but I am having an issue.
Normal filter, like text and date types are properly working but combo filters using JsonStore are not working. here is the sample code.

filter: {
xtype : 'combo',
displayField : 'title',
store : new Ext.data.JsonStore({
root: 'items',
fields: [ {name:'id',type:'int'},'title' ],
data: {"items":[{"id":"1","title":"Concrete"},{"id":"2","title":"Grout"}]}
}),
triggerAction: 'all',
valueField : 'id',
hiddenName : 'id',
typeAhead : true,
name: 'id',
mode : 'local',
filterName: "id"
}This was working with ExtJs 3.2 and GridHeaderFilters version 1.0.12.

daddie888
12 Jan 2011, 5:12 AM
Hello, i use version 2.0.3 of GridHeaderFilters with Ext Js 3.3.1 and have the following problem in IE7 but not in FF3.5
When the window is too small to show the full width of the columns the width of the columns shrinks to show all of the table but not the filters, they are cut off by the next filter/column
See the attachment for an example.

Here my ColumnModel


cm1Midoc = new Ext.grid.ColumnModel({
defaults: {"sortable": true, "menuDisabled":false, "align":"right"},
columns: [
{"id":"id", "header": "id", "hidden": true, "dataIndex": "id", "width": 40, "filter":[{xtype:"numberfield",style: 'text-align: right', emptyText:'van'},{xtype:"numberfield", style: 'text-align: right', emptyText:'tot'}]},
{"header": "rnr13", "dataIndex": "rnr13", "width": 50, filter: [{xtype:"textfield", style: 'text-align: right'}, {xtype:"textfield", style: 'text-align: right'}]},
{"header": "datumlijst", "dataIndex": "datumlijst", "renderer": Ext.util.Format.dateRenderer('d-m-Y'), "width": 40, filter: [{xtype:"datefield", format:'d-m-Y'},{xtype:"datefield", format:'d-m-Y'}]},
{"header": "datvan", "dataIndex": "datvan", "renderer": Ext.util.Format.dateRenderer('d-m-Y'), "width": 40, filter: [{xtype:"datefield", format:'d-m-Y'},{xtype:"datefield", format:'d-m-Y'}]},
{"header": "dattot", "dataIndex": "dattot", "renderer": Ext.util.Format.dateRenderer('d-m-Y'), "width": 40, filter: [{xtype:"datefield", format:'d-m-Y'},{xtype:"datefield", format:'d-m-Y'}]},
{"header": "waarde", "dataIndex": "waarde", "renderer": "Ext.util.Format.number", "width": 30, filter: [{xtype:"numberfield"},{xtype:"numberfield"}]}
]
});

Can anybody give me a hint ?

Thanks !!

Peter

mkraemer
14 Jan 2011, 7:45 AM
Thank you for your extension, d.zucconi.

To avoid that the normal background image of the grid header is stretched when using your extension, i quickly created a new image for the grid header. It looks ok with or without the filter fields enabled, maybe someone else can use it :)

Needed CSS:

/* Fix to avoid the normal 22px-height background image stretching to 48px height: */
.x-grid3-header {
background-image: url('/images/grid3-hrow2-48.gif')!important;
background-position: 0 top;
}

.x-ghf-filter-container .x-form-item{
margin-bottom: 2px;
}Needed image is attached.

Marius

mshussein
22 Jan 2011, 10:10 PM
First up: I love this plugin.

When using Combos and Datefields as filters however, I cannot get them to 'clear'.

If I remove all the text in a datefield/combo filter field, and then modify another filter field, the filter text comes back for the datefield/combo. Once this happens, no matter what I do, i cannot get the filter to clear (unless of course I set the GridPanel stateful:false and I refresh).

Has anyone else experienced this in the past? How did you get around it?


Kindest regards,
mshussein.

Edit: using Ext 3.3.1 and GHF 2.0.3, so this may be an issue?

mshussein
23 Jan 2011, 12:46 AM
Well,

I managed to work around this by changing this:



if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
return;
}else{
this.applyFilter(field);
}


to




if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
this.applyFilter(field);
}else{
this.applyFilter(field);
}


...inside the configure function (Changes were made around line 342).

I know it makes the if statement redundant, but it's easier to keep it like that so I can switch between the two.

Yet to find any issues with the change.

Regards,
mshussein.

daddie888
26 Jan 2011, 9:06 AM
Found a workaround, here is the patch


renderFilterContainer: function(columnId, fcc)
{
if(!this.filterContainers)
this.filterContainers = {};
//Associated column index
var ci = this.grid.getColumnModel().getIndexById(columnId);
//Header TD
var td = this.grid.getView().getHeaderCell(ci);
td = Ext.get(td);
//Patch for field text selection on Mozilla
if(Ext.isGecko){
td.dom.style.MozUserSelect = "text";
}
fcc.width = td.getWidth() - 3;
td.dom.style.verticalAlign = 'top';
//Render filter container

var fc = new Ext.Container(fcc);
fc.render(td);
//Container cache
this.filterContainers[columnId] = fc;
//Fields cache
var height = 0;
if(!this.filterFields)
this.filterFields = {};
var fields = fc.findBy(function(cmp){return !Ext.isEmpty(cmp.filterName);});
if(!Ext.isEmpty(fields))
{
for(var i=0;i<fields.length;i++)
{
var filterName = fields[i].filterName;
this.filterFields[filterName] = fields[i];
height += fields[i].getHeight();
if(!Ext.isGecko){
fields[i].setWidth(fcc.width); //for IE7
}
}
}

d.zucconi
26 Jan 2011, 11:31 PM
Well,

I managed to work around this by changing this:



if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
return;
}else{
this.applyFilter(field);
}


to




if(t=='combo' || t=='datefield'){ //avoid refresh twice for combo select
this.applyFilter(field);
}else{
this.applyFilter(field);
}


...inside the configure function (Changes were made around line 342).

I know it makes the if statement redundant, but it's easier to keep it like that so I can switch between the two.

Yet to find any issues with the change.

Regards,
mshussein.

Yes, this is a patch for this bad behaviour.
The applyMode = 'auto' or = 'change' is now deprecated, I always use applyMode = 'enter', adding also an "apply button" to my grid toolbar.
You can also use the filter configuration attribute "applyFilterEvent" to select the field event that applies filter. At the moment this feature is a little bit restrictive because you can specify only one event listener and it replaces any other listener specified in filter field config. That could be improved in future versions.

qwikso
24 Feb 2011, 2:29 PM
Hi,

please fix memory leak probably caused by typing error (filterContainer -> filterContainers). The this.filterContainer does not exist, so filterContainers' items are never destroyed. This is a very unpleasant bug since the destroyFilters function is executed almost after each action with the filter.



destroyFilters: function()
{
if(this.filterFields)
{
for(var ff in this.filterFields)
{
Ext.destroy(this.filterFields[ff]);
delete this.filterFields[ff];
}
}

if(this.filterContainer)
{
for(var ff in this.filterContainers)
{
Ext.destroy(this.filterContainers[ff]);
delete this.filterContainers[ff];
}
}

}

d.zucconi
25 Feb 2011, 12:05 AM
Hi,

please fix memory leak probably caused by typing error (filterContainer -> filterContainers). The this.filterContainer does not exist, so filterContainers' items are never destroyed. This is a very unpleasant bug since the destroyFilters function is executed almost after each action with the filter.

Thanks for the fix.
I've updated the first page with latest version code.

dolittle
2 Mar 2011, 9:01 AM
Are there plans to support extjs 4?
Do you think many changes are required?

p.s. can you support disabled fields?
patch:
http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=541074&viewfull=1#post541074

d.zucconi
2 Mar 2011, 11:42 PM
Are there plans to support extjs 4?
Do you think many changes are required?

p.s. can you support disabled fields?
patch:
http://www.sencha.com/forum/showthread.php?41658-Grid-header-filters&p=541074&viewfull=1#post541074
Hi,
I've applied your patch to the applyFilter method (with a little change):


...
if(el.disabled && !Ext.isDefined(this.grid.store.baseParams[el.filterName]))
return;

var sValue = this.getFieldValue(el);

if(el.disabled || Ext.isEmpty(sValue))
{
delete this.grid.store.baseParams[el.filterName];
delete this.filters[el.filterName];
}
...

The latest version (2.0.6) is published on the first page of this thread.

About ExtJS 4: I have not tried it yet. I hope to do it soon while waiting for the final release.

Thanks.

astuteq
5 Mar 2011, 3:15 AM
Hello,

I have a problem when using a grid with header filters in a card layout.
This is what I have:

The first panel shows the grid. In my application I have an edit dialog for records in the grid.
In some cases I must reload the store when the grid is hidden.

In this case the filter fields in the header disappear completely when using version 2.0.5.
If I use version 2.0.6, the filter fields are minimized and the trigger is shown.

You can try it here:
http://sandbox.astuteq.de/


- go to the page
- press "reload"
- press "show grid"

source:
http://sandbox.astuteq.de/js/sandbox.js

Any ideas?

Thanks!

Stefan

drian
5 Mar 2011, 6:53 AM
I think there's a bug when resizing the columns, the width of the filter textfield/combo isn't calculated correctly. Instead of using absoulte values which need to be recalculated on every column resize, isn't it better to make the filter 100% width by default?

astuteq
5 Mar 2011, 8:01 AM
I have no width set. And it seems that it is the default setting to make the filter fields 100% of the column width?

astuteq
17 Mar 2011, 1:07 AM
Hello,

could somebody imagine a solution for the problem described in post #116?

Thanks,
Stefan

mirws
28 Apr 2011, 10:50 PM
I'm waiting for Ext 4 support for this plugin!??

hansl1963
6 May 2011, 2:04 AM
Great plugin

Is it possible to apply the filter on the local store (just like the Ext.ux.grid.GridFilters)
I have all the record allready into the grid..

philip142au
14 May 2011, 8:48 PM
Hi, does anyone have this grid working in ExtJS-4? I really like it.
Regards, Philip

philip142au
15 May 2011, 2:39 AM
I discovered the following:

I found that eachColumn in FilterRow.js should change from:

eachColumn: function(func) {
Ext.each(this.grid.getColumnModel().config, func, this);
}

to

eachColumn: function(func) {
Ext.each(this.grid.headerCt.gridDataColumns, func, this);
}


In general to use grid.headerCt in place of getColumnModel()

Also change init

init: function(grid) {
this.grid = grid;
var cm = grid.headerCt;

I guess there's many more changes that have to be done, can anyone help?

Thanks, Philip

johnsonkid
19 May 2011, 9:33 PM
Thanks, that worked! Now I'm having a similar issue when I resize a column. The column in question resizes fine, but the other columns do not resize. I then tried calling the onRender after a resize but all of the columns resize in width but they grow in height two-fold, each time a column resize occurs?

caizhikun
22 May 2011, 2:48 AM
there is a problem i met:
the filter component's width can't fit the header's width,when the first render.



var fields=[{
type: 'string',
name: 'item'
},{
type: 'string',
name: 'description'
},{
type: 'string',
name: 'po'
},{
type: 'string',
name: 'style'
},{
type: 'string',
name: 'size'
},{
type: 'int',
name: 'ysqty'
},{
type: 'int',
name: 'ssqty'
},{
type: 'string',
name: 'remark'
}]
var columns=[{
dataIndex: 'item',
header: 'Item',
filter: {xtype:"textfield", filterName:"CODE"}
},{
dataIndex: 'description',
header: 'Description',
width:300,
filter: {xtype:"textfield", filterName:"CODE"}
},{
dataIndex: 'po',
header: 'PO'
},{
dataIndex: 'style',
header: 'Style'
},{
dataIndex: 'size',
header: 'Size'
},{
dataIndex: 'ysqty',
header: '应收数量'
},{
dataIndex: 'ssqty',
header: '实收数量'
},{
dataIndex: 'remark',
header: '备注'
}]
var data=[['item1','aaaaa','PO1','style1','L',90,85,'SDFDSF'],['item1','aaaaa','PO1','style1','M',70,65,'SDFDSF']
,['item1','aaaaa','PO2','style4','M',70,65,'SDFDSF'],['item2','aaaaa','PO1','style1','M',70,65,'SDFDSF']
,['item2','aaaaa','PO1','style1','M',70,65,'SDFDSF'],['item2','aaaaa','PO1','style1','M',70,65,'SDFDSF']]

var grid = new Ext.grid.GridPanel({
renderTo: 'column-group-grid',
title: 'Sales By Location',
width: 1000,
height: 400,
store: new Ext.data.ArrayStore({
fields: fields,
data: data
}),
columns: columns,
viewConfig: {
forceFit: true
},
plugins: [new Ext.ux.grid.GridHeaderFilters()]
});

caizhikun
22 May 2011, 2:55 AM
this is the image:3Q
26198

gustavo21
23 May 2011, 9:40 AM
Hi, great plugin! but i need to add a button to reset the filters, because if i filter many columns its difficult to click in each field and delete ono by one...
Its that possible to do??

Thanks.

philip142au
26 May 2011, 4:07 AM
Hi!, do you have it working in ExtJS 4?


Thanks, that worked! Now I'm having a similar issue when I resize a column. The column in question resizes fine, but the other columns do not resize. I then tried calling the onRender after a resize but all of the columns resize in width but they grow in height two-fold, each time a column resize occurs?

qwikso
26 May 2011, 1:35 PM
Hi, great plugin! but i need to add a button to reset the filters, because if i filter many columns its difficult to click in each field and delete ono by one...
Its that possible to do??

Thanks.

Just call the resetHeaderFilters(bReload) method on your grid in the button handler function.


{
xtype:'button',
handler : function() {
grid.resetHeaderFilters(true/*or false*/);
}
}

gustavo21
26 May 2011, 9:11 PM
Thanks, but i tried and do nothing... no errors in console either...

qwikso
29 May 2011, 1:19 PM
Thanks, but i tried and do nothing... no errors in console either...

Ok, so only for sure... Are you using the latest version of this plugin? Can you post the minimal code, which does not work for you? Otherwise it's not possible to help you. I've never had any problem with this base functionality.

gustavo21
29 May 2011, 2:31 PM
Hi, i downloaded the plugin las week... so i think it´s the latest version.
I have a grid, and i put a button in the paging toolbar:


bbar: {
xtype: 'paging',
store: 'stConsulta',
pageSize: 10,
displayInfo: true,
items: [
{
xtype: 'tbseparator',
width: 39,
height: 13
},
{
xtype: 'button',
text: 'Borrar Filtros',
handler : function() {
resetHeaderFilters(true);
}
}
]

Thanks!

qwikso
29 May 2011, 11:36 PM
I wanted to see your full grid configuration. More or less you are calling resetHeaderFilters function in the btn handler, but you don't specify any scope. Therefore the code in the button's handler function isn't called in the scope of your grid object. Try this:

bbar: {
xtype: 'paging',
store: 'stConsulta',
pageSize: 10,
displayInfo: true,
items: [
{
xtype: 'tbseparator',
width: 39,
height: 13
},
{
xtype: 'button',
text: 'Borrar Filtros',
scope : this, // or put here reference to your grid instance
handler : function() {
this.resetHeaderFilters(true);
}
}
]

gustavo21
31 May 2011, 12:11 PM
xtype: 'grid',
store: 'stConsulta',
height: 200,
region: 'center',
ref: '../legajos',
plugins: [new Ext.ux.grid.GridHeaderFilters()],
selModel: new Ext.grid.RowSelectionModel({
singleSelect: true
}),
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'Legajo',
header: 'Legajo',
sortable: true,
filter: {xtype:"numberfield", filterName:"filtro_Legajo"},
width: 12,
},
{
xtype: 'gridcolumn',
dataIndex: 'Nombre',
header: 'Apellido, Nombres',
sortable: true,
filter: {xtype:"textfield", filterName:"nombre"},
align: 'left',
width: 50
},
{
xtype: 'gridcolumn',
dataIndex: 'DesDpto',
header: 'Departamento',
sortable: true,
filter: {xtype:"textfield", filterName:"departamento"},
width: 50
},
{
xtype: 'gridcolumn',
dataIndex: 'Tipo',
header: 'Tipo Empleado',
sortable: true,
filter: {xtype:"textfield", filterName:"tip_emp"},
width: 25,
},
{
xtype: 'gridcolumn',
dataIndex: 'Categoria',
header: 'Categoria',
sortable: true,
filter: {xtype:"numberfield", filterName:"categoria"},
width: 15,
},
{
xtype: 'gridcolumn',
dataIndex: 'Localidad',
header: 'Localidad',
sortable: true,
filter: {xtype:"textfield", filterName:"localidad"},
width: 35,
},
{
xtype: 'gridcolumn',
dataIndex: 'FecIng',
header: 'Fecha Ing.',
filter: {xtype:"datefield",format:'d-m-Y', filterName:"ingreso"},
sortable: true,
width: 25
}
],
viewConfig: {
forceFit: true
},
bbar: {
xtype: 'paging',
store: 'stConsulta',
pageSize: 10,
displayInfo: true,
items: [{
xtype: 'tbseparator',
width: 39,
height: 13
},{
xtype: 'button',
text: 'Borrar Filtros',
scope:this,
handler : function() {
this.resetHeaderFilters(true);
}
}]
}
}
]
},

Firebug return:
this.resetHeaderFilters is not a function
chrome://firebug/content/blank.gif this.resetHeaderFilters(true);


The filters are working fine, no problems - no events in console.

Thanks.

qwikso
31 May 2011, 12:25 PM
It cannot work because you did not set any grid reference to the button scope. If you do not really need to use xtype object, this should work:


var grid = new Ext.grid.GridPanel({
store : 'stConsulta',
height : 200,
region : 'center',
ref : '../legajos',
plugins : [new Ext.ux.grid.GridHeaderFilters()],
selModel : new Ext.grid.RowSelectionModel({
singleSelect : true
}),
columns : [{
xtype : 'gridcolumn',
dataIndex : 'Legajo',
header : 'Legajo',
sortable : true,
filter : {
xtype : "numberfield",
filterName : "filtro_Legajo"
},
width : 12
}, {
xtype : 'gridcolumn',
dataIndex : 'Nombre',
header : 'Apellido, Nombres',
sortable : true,
filter : {
xtype : "textfield",
filterName : "nombre"
},
align : 'left',
width : 50
}, {
xtype : 'gridcolumn',
dataIndex : 'DesDpto',
header : 'Departamento',
sortable : true,
filter : {
xtype : "textfield",
filterName : "departamento"
},
width : 50
}, {
xtype : 'gridcolumn',
dataIndex : 'Tipo',
header : 'Tipo Empleado',
sortable : true,
filter : {
xtype : "textfield",
filterName : "tip_emp"
},
width : 25
}, {
xtype : 'gridcolumn',
dataIndex : 'Categoria',
header : 'Categoria',
sortable : true,
filter : {
xtype : "numberfield",
filterName : "categoria"
},
width : 15
}, {
xtype : 'gridcolumn',
dataIndex : 'Localidad',
header : 'Localidad',
sortable : true,
filter : {
xtype : "textfield",
filterName : "localidad"
},
width : 35
}, {
xtype : 'gridcolumn',
dataIndex : 'FecIng',
header : 'Fecha Ing.',
filter : {
xtype : "datefield",
format : 'd-m-Y',
filterName : "ingreso"
},
sortable : true,
width : 25
}],
viewConfig : {
forceFit : true
},
bbar : {
xtype : 'paging',
store : 'stConsulta',
pageSize : 10,
displayInfo : true,
items : [{
xtype : 'tbseparator',
width : 39,
height : 13
}, {
xtype : 'button',
text : 'Borrar Filtros',
handler : function() {
grid.resetHeaderFilters(true);
}
}]
}
});


Otherwise you can set element ID and call it in the button handler function:



{
xtype : 'grid',
id : 'myGrid',
store : 'stConsulta',
height : 200,
region : 'center',
ref : '../legajos',
plugins : [new Ext.ux.grid.GridHeaderFilters()],
selModel : new Ext.grid.RowSelectionModel({
singleSelect : true
}),
columns : [{
xtype : 'gridcolumn',
dataIndex : 'Legajo',
header : 'Legajo',
sortable : true,
filter : {
xtype : "numberfield",
filterName : "filtro_Legajo"
},
width : 12
}, {
xtype : 'gridcolumn',
dataIndex : 'Nombre',
header : 'Apellido, Nombres',
sortable : true,
filter : {
xtype : "textfield",
filterName : "nombre"
},
align : 'left',
width : 50
}, {
xtype : 'gridcolumn',
dataIndex : 'DesDpto',
header : 'Departamento',
sortable : true,
filter : {
xtype : "textfield",
filterName : "departamento"
},
width : 50
}, {
xtype : 'gridcolumn',
dataIndex : 'Tipo',
header : 'Tipo Empleado',
sortable : true,
filter : {
xtype : "textfield",
filterName : "tip_emp"
},
width : 25
}, {
xtype : 'gridcolumn',
dataIndex : 'Categoria',
header : 'Categoria',
sortable : true,
filter : {
xtype : "numberfield",
filterName : "categoria"
},
width : 15
}, {
xtype : 'gridcolumn',
dataIndex : 'Localidad',
header : 'Localidad',
sortable : true,
filter : {
xtype : "textfield",
filterName : "localidad"
},
width : 35
}, {
xtype : 'gridcolumn',
dataIndex : 'FecIng',
header : 'Fecha Ing.',
filter : {
xtype : "datefield",
format : 'd-m-Y',
filterName : "ingreso"
},
sortable : true,
width : 25
}],
viewConfig : {
forceFit : true
},
bbar : {
xtype : 'paging',
store : 'stConsulta',
pageSize : 10,
displayInfo : true,
items : [{
xtype : 'tbseparator',
width : 39,
height : 13
}, {
xtype : 'button',
text : 'Borrar Filtros',
handler : function() {
var grid = Ext.getCmp('myGrid');
grid.resetHeaderFilters(true);
}
}]
}
}

gustavo21
3 Jun 2011, 4:26 PM
Thanks, now works OK!

qwikso
1 Jul 2011, 1:08 AM
Hi d.zucconi,
are you going to migrate this great plugin to the pure ExtJS 4.0+ version (without sandboxing)?

Thanks!
Best regards, qwx.

d.zucconi
1 Jul 2011, 1:45 AM
Hi,
Unfortunatly at the moment we're not developing on Ext 4 yet.
I think that this plugin will be migrated to be compatible with new Ext 4 grids, but at the moment I'm not sure about "when".

qooleot
23 Aug 2011, 1:26 PM
For some reason in IE (at least IE6), when I had filters (and I didn't do a full test case, but I had 2 filters in each column) it wouldn't resize the filters but it worked in firefox. I added the code in red bold and it now works, in case anyone else runs into this:


onColResize: function(index, iWidth){
if(!this.filterContainers)
return;
var colId = this.grid.getColumnModel().getColumnId(index);
var cnt = this.filterContainers[colId];
if(cnt)
{
if(isNaN(iWidth))
iWidth = 0;
var filterW = (iWidth < 3) ? 0 : (iWidth - 3);
cnt.setWidth(filterW);
for (var cnt_item_cnt = 0; cnt_item_cnt < cnt.items.length; cnt_item_cnt++) {
cnt.items.items[cnt_item_cnt].setWidth(filterW);
}
//Thanks to ob1
cnt.doLayout(false,true);
}
},

mkraemer
30 Aug 2011, 8:25 AM
In case one is using this plugin in combination with a grid which has dynamically sized columns (via forceFit), it is not sufficient to react to the changed size of a single column. To resize all filters accordingly to the columns change around line 150:

scope: this,
render: this.onRender,
resize: this.onResize,
//All columns have to be resized if a single one is modified
//columnresize: this.onColResize,
columnresize: this.onResize,
reconfigure: this.onReconfigure,
beforedestroy: this.destroyFilters

To react to the hiding/unhiding of columns, onColHidden (around line 600) has to be modified:
onColHidden: function(cm, index, bHidden){
this.grid.getView().updateColumnHidden(index, bHidden);
this.onResize(); //Recalculate the widths of all columns
},

dougboyd
3 Oct 2011, 1:10 PM
Heya D

Great plugin. However, I'm really keen to see it migrated to the 4.0x platform and am curious if there's a roadmap/timeframe. I've pulled the code apart enough to recognise that the basic paradigm of columns is completely different in 4.0x and am considering rewriting myself but don't want to reinvent the wheel if it is going to be released in the near future.

And comment or direction?

Cheers

Doug

d.zucconi
3 Oct 2011, 10:12 PM
Hi,
We think to begin to migrate our Ext-ux library (wich includes the GridHeaderFilters plugin) to Ext4 in the next 2 or 3 months.
So probably at the end of october or in the first half of november we could have a prototype of GridHeaderFilter plugin developed for Ext4.
We hope to be able to mantain our develop plan.
Thanks to every one that supports our work in this thread.

d.zucconi
14 Oct 2011, 7:55 AM
Hi all,
A ExtJS 4 preview version of this plugin is now available on a new thread:
http://www.sencha.com/forum/showthread.php?150918-Grid-Header-Filters&p=660276#post660276
(http://www.sencha.com/forum/showthread.php?150918-Grid-Header-Filters&p=660276#post660276)The plugin has been rewritten and some functionality removed or updated.
Please check the new thread for further details and news.

sajidalimudassar
18 Oct 2011, 2:04 AM
Thank you d.zucconi for the preview release.

vann
30 Dec 2011, 9:16 AM
Hello All and thanks in advance,

I am filtering on a text field and want to apply the filter after each keyup

columns: [{
header: "xxx ID",
dataIndex: 'xxx_id',
sortable: true,
width:75,
css:'vertical-align:middle;',
filter:{
xtype:"textfield",
filterName:"FILTER_id",
applyFilterEvent:'onkeyup'
}
}

Does anyone know how I can get this effect?

thanks,
Van

vann
30 Dec 2011, 11:24 AM
found the answer to my problem. Completely forgot about this setting: enableKeyEvents: true

filter:{
xtype:"textfield",
filterName:"FILTER_synopsis",
enableKeyEvents: true,
applyFilterEvent:'keyup'
}

HarryC
11 Jan 2012, 11:20 AM
Damiano, thank you so much for this plugin. I've been using ExtJS for 3 years and only just discovered it now. It's one of the best plugins I've seen and I wish I'd found it sooner.

Thank you for your hard work on this.

ing.amdangelo
20 Jan 2012, 8:17 AM
Where I Download the plugin for the Ext.3 version ??

Dan Dragut
15 Feb 2012, 10:15 AM
Hi,

First of all, thanks for making the plugin available, I've just used recently in my project.

I found the need to be able to submit the filter values in a single field, and I believe a couple of other people expressed similar earlier in the thread, and I made this change allowing for the filter values to be packaged into a single Json object (optional), instead of separate filter fields - thought it may be useful to others. I haven't fully tested to see what happens when the field is disabled, but it seems to work for me, so here it is the diff for it.


130a131,136> * @cfg {String} submitSingleObject
> * If specified, submits filter values under this one parameter name (Json encoded), instead of separate parameters (default behavior).
> */
> submitSingleObject: null,
>
> /**
682c688,690
< this.grid.store.baseParams[el.filterName] = sValue;
---
> if (!Ext.isString(this.submitSingleObject))
> this.grid.store.baseParams[el.filterName] = sValue;
>
718a727
>
721a731,736
>
> // Single JSON object...
> if (Ext.isString(this.submitSingleObject))
> slp[this.submitSingleObject] = Ext.encode(this.filters);
>
> // Reload store...


I'm still looking for a way to re-focus the last filter field after the store reload (masked), using the search triggerd by ENTER key...

Dan Dragut
15 Feb 2012, 1:10 PM
Problem with my earlier change, to make the filter persistent when using a grid with a PagingToolbar - initial filtering would work fine, but paging through the contents would loose the filters...

http://docs.sencha.com/ext-js/3-4/#!/api/Ext.data.Store-method-setBaseParam


// Single JSON object...
if (Ext.isString(this.submitSingleObject))
this.grid.store.setBaseParam(this.submitSingleObject, Ext.encode(this.filters));

// Reload store...
this.grid.store.load({params: slp});

csextjs
25 Feb 2012, 11:41 AM
Nice plugin.

Does this plugin works with Columngridheader AND LockingGridView?
If anyone worked on this plugin with Columngridheader AND LockingGridView,
could you please let me know.

Thank you.

KakaxiTaDie
4 Mar 2012, 1:25 AM
Hello all!!!I've a dynamic grid (json configuired) created as follow:
xgrid = new Ext.ux.GridExtension({ border:false ,stateful:false ,store:store ,loadMask: true ,stripeRows: true ,plugins: [new Ext.ux.grid.GridHeaderFilters()] ,columns:[] ,viewConfig:{onDataChange: function(){ var columns = []; columns.push(smodel); for (var i = 0; i < this.ds.reader.jsonData.totcol; i++) { eval("this.ds.reader.jsonData.columns[i].renderer = "+this.ds.reader.jsonData.columns[i].renderer); columns.push(this.ds.reader.jsonData.columns[i]); } this.cm.setConfig(columns); this.syncFocusEl(0); }, forceFit:true, emptyText: 'No records.'} ,tbar: tb ,sm : smodel ,bbar : new Ext.PagingToolbar({ store: store ,displayInfo:true ,pageSize:Prowperpage })});... and this is my json..
{"metaData": {"totalProperty": "total","root": "records","fields": [{"name":"objectUser","mapping":"Utilizzatore","type":"string"},{"name":"objectCode","mapping":"Oggetto","type":"string"},{"name":"userID","mapping":"Utente\/*all","type":"string"},{"name":"applicationArea","mapping":"Area Applicativa","type":"string"},{"name":"mKey","mapping":"mKey","type":"string"}]},"success": true,"total": 164,"records": [-------],"totcol":4,"columns": [{"dataIndex":"objectUser","header":"Utilizzatore","filter":{"xtype":"textfield"},"decorated":false},{"dataIndex":"objectCode","header":"Oggetto","filter":{"xtype":"textfield"},"decorated":false},{"dataIndex":"userID","header":"Utente\/*all","filter":{"xtype":"textfield"},"decorated":false},{"dataIndex":"applicationArea","header":"Area Applicativa","filter":{"xtype":"textfield"},"decorated":false},{"dataIndex":"mKey","header":"mKey","hidden":true}]}... but i don't see any filter in grid... without errors...Anyone can help?? Please..I've using EXT 3.3.0ThanksEDIT..In firebug i see that:When the plugin is inizialized, the column model does not exist yet. This is due to the type of column model (loaded via json)??? Hi!I'm using EXTJS 4.0 now.I've a dynamic grid (json configuired) which need filters on the header .Then I get this plugins and see your messages.I know the plugins cannot help solving this problem.Have you ever done it ? and can you help me ?thanks!

sofia@apexchat.com
23 Jul 2012, 1:17 PM
Hi,
I am using a combo box as a filter in a column. When I select a value from the combo box, it does not show up and I see a blank value selected. Any idea why this is happening?

Thanks
Sofia

qooleot
8 Aug 2012, 6:26 AM
I'm using this plugin with multiple filters per field (and local stores for comboboxes) in ext 4.1.1.

I made two changes to this plugin that might be useful for other folks:



var newSf = new Ext.util.Filter({
root: this.filterRoot,
property: fn,
value: filters[fn],
anyMatch: true,
label: field.fieldLabel
});




A lot of people use the anyMatch plugin for comboboxes, so I wanted it here for consistency. If we add this to the library, we should make it a property upon initializing it instead of just hardcoding it to true though.

Within 'renderFilters' function:


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];
if (initValue == undefined || initValue == null) {
initValue = fc.value;
}


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);
}




I pass my initial values for combobox filters via the value property:

{xtype: 'combo', value: 'contains', store: [..]...}

and that change was necessary so it actually picked up that initial value.

gayathr
14 Nov 2012, 2:12 AM
I tried to implement Filter as first row inside the grid with the help of this plug in in Ext js 4.1. But this is not working. Can you please let me know whether this plugin will work for 4.1 or not

gayathr
14 Nov 2012, 2:13 AM
I tried to implement Filter as first row inside the grid with the help of this plug in in Ext js 4.1. But this is not working. Can you please let me know whether this plugin will work for 4.1 or not

d.zucconi
14 Nov 2012, 3:09 AM
I tried to implement Filter as first row inside the grid with the help of this plug in in Ext js 4.1. But this is not working. Can you please let me know whether this plugin will work for 4.1 or not
​http://www.sencha.com/forum/showthread.php?150918

gayathr
14 Nov 2012, 6:33 AM
Thanks

Now filters are coming inside the grid. But the filter functionlity is not working. I mean i am unable to filter. Also i am unable to reposition the columns. Please suggest what needs to do. I am new to ext js

Sabareesh
4 Dec 2012, 8:22 PM
Hi

I am using Extjs version 3 . Grid filter is working fine when i use the below coding

var filterRow = new Ext.ux.grid.FilterRow({
// automatically refilter store when records are added
refilterOnStoreUpdate: true
});

var grid= new Ext.grid.GridPanel({
store : artistDashboardStore,
plugins : [filterRow]});

but if i put the grid inside a panel like the below it is not working.

var artistDshTabPanel = new Ext.TabPanel({
activeTab : 0,
items : [{
title : 'ABC',
items :[grid]
}]
});

Any help ?

Thanks
Sabareesh

viniscius
18 Dec 2012, 5:52 AM
Any luck on the online demo? The old link doesn't seem to be working...

Thanks in advance.
Regards.

harshp
31 Jan 2013, 4:39 AM
Hi,

Please check below code, I can see grid filter row , but it is not filtering data.
Do I need to write any code for filtering data from data store.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title> New Document </title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">


<link rel="stylesheet" type="text/css" href="css/ext-all.css" />
<script type="text/javascript" src="adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext-all.js"></script>

<script type="text/javascript" src="ext-all.js"></script>


<script type="text/javascript" src="GridHeaderFilters.js"></script>


<script type="text/javascript">
Ext.onReady(function() {


// sample static data for the store
var fields=[{
type: 'string',
name: 'item'
},{
type: 'string',
name: 'description'
},{
type: 'string',
name: 'po'
},{
type: 'string',
name: 'style'
},{
type: 'string',
name: 'size'
},{
type: 'int',
name: 'ysqty'
},{
type: 'int',
name: 'ssqty'
},{
type: 'string',
name: 'remark'
}]
var columns=[{
dataIndex: 'item',
header: 'Item',
filter: {xtype:"textfield", filterName:"CODE"},
enableKeyEvents: true
},{
dataIndex: 'description',
header: 'Description',
width:300,
filter: {xtype:"textfield", filterName:"CODE"},
enableKeyEvents: true
},{
dataIndex: 'po',
header: 'PO'
},{
dataIndex: 'style',
header: 'Style'
},{
dataIndex: 'size',
header: 'Size'
},{
dataIndex: 'ysqty',
header: 'ysqty'
},{
dataIndex: 'ssqty',
header: 'ssqty'
},{
dataIndex: 'remark',
header: 'remark'
}]
var data=[['item1','aaaaa','PO1','style1','L',90,85,'SDFDSF'],['item1','aaaaa','PO1','style1','M',70,65,'SDFDSF']
,['item1','aaaaa','PO2','style4','M',70,65,'SDFDSF'],['item2','aaaaa','PO1','style1','M',70,65,'SDFDSF']
,['item2','aaaaa','PO1','style1','M',70,65,'SDFDSF'],['item2','aaaaa','PO1','style1','M',70,65,'SDFDSF']]

var grid = new Ext.grid.GridPanel({
renderTo: 'grid',
title: 'Sales By Location',
width: 1000,
height: 400,
store: new Ext.data.ArrayStore({
fields: fields,
data: data
}),
columns: columns,
viewConfig: {
forceFit: true
},
plugins: [new Ext.ux.grid.GridHeaderFilters()]
});

})
</script>
</head>


<body> <div id="grid"></div>

</body>
</html>

bizcatalyst
6 Mar 2013, 12:35 PM
Hello, i use version 2.0.3 of GridHeaderFilters with Ext Js 3.3.1 and have the following problem in IE7 but not in FF3.5
When the window is too small to show the full width of the columns the width of the columns shrinks to show all of the table but not the filters, they are cut off by the next filter/column
See the attachment for an example.

Here my ColumnModel


cm1Midoc = new Ext.grid.ColumnModel({
defaults: {"sortable": true, "menuDisabled":false, "align":"right"},
columns: [
{"id":"id", "header": "id", "hidden": true, "dataIndex": "id", "width": 40, "filter":[{xtype:"numberfield",style: 'text-align: right', emptyText:'van'},{xtype:"numberfield", style: 'text-align: right', emptyText:'tot'}]},
{"header": "rnr13", "dataIndex": "rnr13", "width": 50, filter: [{xtype:"textfield", style: 'text-align: right'}, {xtype:"textfield", style: 'text-align: right'}]},
{"header": "datumlijst", "dataIndex": "datumlijst", "renderer": Ext.util.Format.dateRenderer('d-m-Y'), "width": 40, filter: [{xtype:"datefield", format:'d-m-Y'},{xtype:"datefield", format:'d-m-Y'}]},
{"header": "datvan", "dataIndex": "datvan", "renderer": Ext.util.Format.dateRenderer('d-m-Y'), "width": 40, filter: [{xtype:"datefield", format:'d-m-Y'},{xtype:"datefield", format:'d-m-Y'}]},
{"header": "dattot", "dataIndex": "dattot", "renderer": Ext.util.Format.dateRenderer('d-m-Y'), "width": 40, filter: [{xtype:"datefield", format:'d-m-Y'},{xtype:"datefield", format:'d-m-Y'}]},
{"header": "waarde", "dataIndex": "waarde", "renderer": "Ext.util.Format.number", "width": 30, filter: [{xtype:"numberfield"},{xtype:"numberfield"}]}
]
});

Can anybody give me a hint ?

Thanks !!

Peter

Thanks for the example using multiple filters in one column, now I can do numeric and date ranges and display them, Yay!

mthaxmiller
3 May 2013, 12:56 PM
Does anyone have an example of hiding the filters for the latest version of this plugin? I have a button to show/hide the filters and this works for that:
toggleFilters: function(bShow) {
for(fc in this.filterContainers) {
var container = this.filterContainers[fc];
if(bShow) {
container.show();
} else {
container.hide();
}
}

}

However, if I call toggleFilters to hide them when the grid is first rendered the above does not work. Any ideas on how to fix this issue? I tried adding doLayout and syncSize, still no luck.

wm003
7 May 2013, 7:41 AM
Can you try to use it in the "afterrender" event?

mthaxmiller
7 May 2013, 9:39 AM
Thanks for replying....
Adding a call to toggle the filters in the afterrender event only works if we add a 2 second delay. Something in the DOM is not be refreshed to hide the filters, if you view the filters using firebug the hidden attribute is true. Any more ideas?

stetou
28 May 2013, 12:19 PM
Ultraman .... then you _must_ know Giant Robot! .. yes, I am showing my age ...

The filter is just sending the POST params .. you have to tell your app (server side) what to do with the information.

Regards,
Scott.

That is important information...but I don't figure what you mean....
The post is on a json file
http://.../antidote.json?start=0&antidote=Thiosulfate

Can't see what I can do...
Can you please give more details?
Thanks in advance

scottmartin
28 May 2013, 12:25 PM
The filter information is sent in the header:

ex:


filter:[{"property":"user_name","value":"admin","type":"string","operator":"like"}]


The server side would need to parse this and then apply the proper filter on the DB/table and send the filtered data back to the client

Scott.

stetou
29 May 2013, 5:01 AM
Thanks for the details.
I thought the filter was managed on client side directly inside the store (geoext.featurestore...a geojson)

stetou
4 Jun 2013, 12:21 PM
I got it working.
I need to launch a function when the value of a combobox as changed. I tried to use a listener on the combo without success (see code below). What is the right way to know when the value changed?


filter:
{
xtype: "combo",
store: liste_rss,
valueField: 'valeur',
displayField: 'valeur',
triggerAction: 'all',
listeners:
{
select://also tried with 'change'
{
fn:function(combo, value)
{
alert('allo');
}
}
}
}

stetou
5 Jun 2013, 10:30 AM
It seems that the combo's listener is not working inside the filter definition.
Please tell me if this is a bug.