Skip to content

Instantly share code, notes, and snippets.

@aghuddleston
Created August 8, 2012 19:03
Show Gist options
  • Save aghuddleston/3297619 to your computer and use it in GitHub Desktop.
Save aghuddleston/3297619 to your computer and use it in GitHub Desktop.
Ext JS 4 Grid Search Plugin originally by Saki and ported by Nathan LeBlanc for Ext JS 4
One bugfix
http://www.sencha.com/forum/showthread.php?23615-Grid-Search-Plugin&p=799141&viewfull=1#post799141
For datecolumns like:
,{
text:'date',
dataIndex:'datecreated',
xtype:'datecolumn',
format:'d.m.Y H:i'
}
// grid's store filter
if('local' === this.mode) {
store.clearFilter();
if(val) {
store.filterBy(function(r) {
var retval = false;
this.menu.items.each(function(item) {
if(!item.checked || retval) {
return;
}
var rv = r.get(item.dataIndex);
var cformat = this.grid.columns[Ext.Array.indexOf(Ext.Array.pluck(this.grid.columns, 'dataIndex'), item.dataIndex)].format;
rv = rv instanceof Date ? Ext.Date.format(rv, this.dateFormat || cformat) : rv;
var re = new RegExp(val, 'gi');
retval = re.test(rv);
}, this);
if(retval) {
return true;
}
return retval;
}, this);
}
else {
}
}
//How to use
http://www.sencha.com/forum/showthread.php?23615-Grid-Search-Plugin&p=623857&viewfull=1#post623857
var searching = {
ftype: 'searching',
minChars: 2,
mode: 'local'
};
var grid = Ext.create('Ext.grid.Panel', {
store: store,
stateful: true,
stateId: 'stateGrid',
features: [searching],
columns: [
{
text : 'Company',
flex : 1,
sortable : false,
dataIndex: 'company'
}
....
One enhancement:
http://www.sencha.com/forum/showthread.php?23615-Grid-Search-Plugin&p=799070&viewfull=1#post799070
Ext.each(columns, function(column) {
var disable = false;
if(column.text && column.dataIndex && column.dataIndex != '') {
Ext.each(this.disableIndexes, function(item) {
disable = disable ? disable : item === column.dataIndex;
});
if(!disable) {
if(typeof column.searchable != 'undefined' && column.searchable == false) {
disable = true;
}
}
if(!disable) {
menu.add({
xtype: 'menucheckitem',
text: column.text,
hideOnClick: false,
group:group,
checked: 'all' === this.checkIndexes,
dataIndex: column.dataIndex,
});
}
}
}, this);
this.columns = [{
text:'ID',
dataIndex:'id',
width:50,
searchable:false
},{.....
// JavaScript Document// vim: ts=4:sw=4:nu:fdc=4:nospell
/**
* Search plugin for Ext.grid.GridPanel, Ext.grid.EditorGrid ver. 2.x or subclasses of them
*
* @author Ing. Jozef Sakalos
* @copyright (c) 2008, by Ing. Jozef Sakalos
* @date 17. January 2008
* @version $Id: Ext.ux.grid.Search.js 220 2008-04-29 21:46:51Z jozo $
*
* @license Ext.ux.grid.Search is licensed under the terms of
* the Open Source LGPL 3.0 license. Commercial use is permitted to the extent
* that the code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* License details: http://www.gnu.org/licenses/lgpl.html
*/
/*
Revised for Ext 4
by Nathan LeBlanc
on July 8, 2011
*/
Ext.define('Ext.ux.grid.feature.Searching', {
extend: 'Ext.grid.feature.Feature',
alias: 'feature.searching',
/**
* cfg {Boolean} autoFocus true to try to focus the input field on each store load (defaults to undefined)
*/
/**
* @cfg {String} searchText Text to display on menu button
*/
searchText:'Search',
/**
* @cfg {String} searchTipText Text to display as input tooltip. Set to '' for no tooltip
*/
searchTipText:'Type a text to search and press Enter',
/**
* @cfg {String} selectAllText Text to display on menu item that selects all fields
*/
selectAllText:'Select All',
/**
* @cfg {String} position Where to display the search controls. Valid values are top and bottom (defaults to bottom)
* Corresponding toolbar has to exist at least with mimimum configuration tbar:[] for position:top or bbar:[]
* for position bottom. Plugin does NOT create any toolbar.
*/
position:'bottom',
/**
* @cfg {String} iconCls Icon class for menu button (defaults to icon-magnifier)
*/
iconCls:'icon-magnifier',
/**
* @cfg {String/Array} checkIndexes Which indexes to check by default. Can be either 'all' for all indexes
* or array of dataIndex names, e.g. ['persFirstName', 'persLastName']
*/
checkIndexes:'all',
/**
* @cfg {Array} disableIndexes Array of index names to disable (not show in the menu), e.g. ['persTitle', 'persTitle2']
*/
disableIndexes:[],
/**
* @cfg {String} dateFormat how to format date values. If undefined (the default)
* date is formatted as configured in colummn model
*/
dateFormat:undefined,
/**
* @cfg {Boolean} showSelectAll Select All item is shown in menu if true (defaults to true)
*/
showSelectAll:true,
/**
* @cfg {String} menuStyle Valid values are 'checkbox' and 'radio'. If menuStyle is radio
* then only one field can be searched at a time and selectAll is automatically switched off.
*/
menuStyle:'checkbox',
/**
* @cfg {Number} minChars minimum characters to type before the request is made. If undefined (the default)
* the trigger field shows magnifier icon and you need to click it or press enter for search to start. If it
* is defined and greater than 0 then maginfier is not shown and search starts after minChars are typed.
*/
/**
* @cfg {String} minCharsTipText Tooltip to display if minChars is > 0
*/
minCharsTipText:'Type at least {0} characters',
/**
* @cfg {String} mode Use 'remote' for remote stores or 'local' for local stores. If mode is local
* no data requests are sent to server the grid's store is filtered instead (defaults to 'remote')
*/
mode:'remote',
/**
* @cfg {Array} readonlyIndexes Array of index names to disable (show in menu disabled), e.g. ['persTitle', 'persTitle2']
*/
/**
* @cfg {Number} width Width of input field in pixels (defaults to 100)
*/
width:100,
/**
* @cfg {Object} paramNames Params name map (defaults to {fields:'fields', query:'query'}
*/
paramNames: {
fields:'fields'
,query:'query'
},
/**
* @cfg {String} shortcutKey Key to fucus the input field (defaults to r = Sea_r_ch). Empty string disables shortcut
*/
shortcutKey:'r',
/**
* @cfg {String} shortcutModifier Modifier for shortcutKey. Valid values: alt, ctrl, shift (defaults to alt)
*/
shortcutModifier:'alt',
/**
* @cfg {String} align 'left' or 'right' (defaults to 'left')
*/
/**
* @cfg {Number} minLength force user to type this many character before he can make a search
*/
/**
* @cfg {Ext.Panel/String} toolbarContainer Panel (or id of the panel) which contains toolbar we want to render
* search controls to (defaults to this.grid, the grid this plugin is plugged-in into)
*/
attachEvents: function() {
this.grid = this.view.up('gridpanel');
if(this.grid.rendered)
this.onRender();
else
this.grid.on('render', this.onRender, this);
},
onRender:function() {
var panel = this.toolbarContainer || this.grid;
var tb = 'bottom' === this.position ? panel.getDockedItems('toolbar[dock="bottom"]') : panel.getDockedItems('toolbar[dock="top"]');
if(tb.length > 0)
tb = tb[0]
else {
tb = Ext.create('Ext.toolbar.Toolbar', {dock: this.position});
panel.addDocked(tb);
}
// add menu
this.menu = Ext.create('Ext.menu.Menu');
// handle position
if('right' === this.align) {
tb.add('->');
}
else {
if(0 < tb.items.getCount()) {
tb.add('-');
}
}
// add menu button
tb.add({
text:this.searchText
,menu:this.menu
,iconCls:this.iconCls
});
// add input field (TwinTriggerField in fact)
this.field = Ext.create('Ext.form.TwinTriggerField', {
width:this.width,
qtip: 'ddd',
selectOnFocus:undefined === this.selectOnFocus ? true : this.selectOnFocus,
trigger1Cls:'x-form-clear-trigger',
trigger2Cls:this.minChars ? 'x-hidden' : 'x-form-search-trigger',
onTrigger1Click: Ext.bind(this.onTriggerClear, this),
onTrigger2Click: this.minChars ? Ext.emptyFn : Ext.bind(this.onTriggerSearch, this),
minLength:this.minLength
});
// install event handlers on input field
this.field.on('render', function() {
var qtip = this.minChars ? Ext.String.format(this.minCharsTipText, this.minChars) : this.searchTipText;
Ext.QuickTips.register({
target: this.field.inputEl,
text: qtip
});
if(this.minChars) {
this.field.el.on({scope:this, buffer:300, keyup:this.onKeyUp});
}
// install key map
var map = new Ext.KeyMap(this.field.el, [{
key:Ext.EventObject.ENTER
,scope:this
,fn:this.onTriggerSearch
},{
key:Ext.EventObject.ESC
,scope:this
,fn:this.onTriggerClear
}]);
map.stopEvent = true;
}, this, {single:true});
tb.add(this.field);
// reconfigure
this.reconfigure();
// keyMap
if(this.shortcutKey && this.shortcutModifier) {
var shortcutEl = this.grid.getEl();
var shortcutCfg = [{
key:this.shortcutKey
,scope:this
,stopEvent:true
,fn:function() {
this.field.focus();
}
}];
shortcutCfg[0][this.shortcutModifier] = true;
this.keymap = new Ext.KeyMap(shortcutEl, shortcutCfg);
}
if(true === this.autoFocus) {
this.grid.store.on({scope:this, load:function(){this.field.focus();}});
}
} // eo function onRender
// }}}
// {{{
/**
* field el keypup event handler. Triggers the search
* @private
*/
,onKeyUp:function() {
var length = this.field.getValue().toString().length;
if(0 === length || this.minChars <= length) {
this.onTriggerSearch();
}
} // eo function onKeyUp
// }}}
// {{{
/**
* private Clear Trigger click handler
*/
,onTriggerClear:function() {
if(this.field.getValue()) {
this.field.setValue('');
this.field.focus();
this.onTriggerSearch();
}
} // eo function onTriggerClear
// }}}
// {{{
/**
* private Search Trigger click handler (executes the search, local or remote)
*/
,onTriggerSearch:function() {
if(!this.field.isValid()) {
return;
}
var val = this.field.getValue(),
store = this.grid.store,
proxy = store.getProxy();
// grid's store filter
if('local' === this.mode) {
store.clearFilter();
if(val) {
store.filterBy(function(r) {
var retval = false;
this.menu.items.each(function(item) {
if(!item.checked || retval) {
return;
}
var rv = r.get(item.dataIndex);
rv = rv instanceof Date ? Ext.Date.format(rv, this.dateFormat || r.fields.get(item.dataIndex).dateFormat) : rv;
var re = new RegExp(val, 'gi');
retval = re.test(rv);
}, this);
if(retval) {
return true;
}
return retval;
}, this);
}
else {
}
}
// ask server to filter records
// your proxy must be a Server proxy
else if(proxy instanceof Ext.data.proxy.Server) {
// clear start (necessary if we have paging)
if(store.lastOptions && store.lastOptions.params) {
store.lastOptions.params[store.paramNames.start] = 0;
}
// get fields to search array
var fields = [];
this.menu.items.each(function(item) {
if(item.checked && item.dataIndex) {
fields.push(item.dataIndex);
}
});
// add fields and query to baseParams of store
delete(proxy.extraParams[this.paramNames.fields]);
delete(proxy.extraParams[this.paramNames.query]);
if (store.lastOptions && store.lastOptions.params) {
delete(proxy.lastOptions.params[this.paramNames.fields]);
delete(proxy.lastOptions.params[this.paramNames.query]);
}
if(fields.length) {
proxy.extraParams[this.paramNames.fields] = Ext.encode(fields);
proxy.extraParams[this.paramNames.query] = val;
}
// reload store
store.load();
}
} // eo function onTriggerSearch
// }}}
// {{{
/**
* @param {Boolean} true to disable search (TwinTriggerField), false to enable
*/
,setDisabled:function() {
this.field.setDisabled.apply(this.field, arguments);
} // eo function setDisabled
// }}}
// {{{
/**
* Enable search (TwinTriggerField)
*/
,enable:function() {
this.setDisabled(false);
} // eo function enable
// }}}
// {{{
/**
* Enable search (TwinTriggerField)
*/
,disable:function() {
this.setDisabled(true);
} // eo function disable
// }}}
// {{{
/**
* private (re)configures the plugin, creates menu items from column model
*/
,reconfigure:function() {
// {{{
// remove old items
var menu = this.menu;
menu.removeAll();
// add Select All item plus separator
if(this.showSelectAll && 'radio' !== this.menuStyle) {
menu.add({
xtype: 'menucheckitem',
text:this.selectAllText,
checked:!(this.checkIndexes instanceof Array),
hideOnClick:false,
handler:function(item) {
var checked = item.checked;
item.parentMenu.items.each(function(i) {
if(item !== i && i.setChecked && !i.disabled) {
i.setChecked(checked);
}
});
}
},'-');
}
// }}}
// {{{
// add new items
var columns = this.grid.headerCt.items.items;
var group = undefined;
if('radio' === this.menuStyle) {
group = 'g' + (new Date).getTime();
}
Ext.each(columns, function(column) {
var disable = false;
if(column.text && column.dataIndex && column.dataIndex != '') {
Ext.each(this.disableIndexes, function(item) {
disable = disable ? disable : item === column.dataIndex;
});
if(!disable) {
menu.add({
xtype: 'menucheckitem',
text: column.text,
hideOnClick: false,
group:group,
checked: 'all' === this.checkIndexes,
dataIndex: column.dataIndex,
});
}
}
}, this);
// }}}
// {{{
// check items
if(this.checkIndexes instanceof Array) {
Ext.each(this.checkIndexes, function(di) {
var item = menu.items.find(function(itm) {
return itm.dataIndex === di;
});
if(item) {
item.setChecked(true, true);
}
}, this);
}
// }}}
// {{{
// disable items
if(this.readonlyIndexes instanceof Array) {
Ext.each(this.readonlyIndexes, function(di) {
var item = menu.items.find(function(itm) {
return itm.dataIndex === di;
});
if(item) {
item.disable();
}
}, this);
}
// }}}
} // eo function reconfigure
// }}}
}); // eo extend
// eof
@rupamkhaitan
Copy link

I Just want the search functionality to be used, basically when user type something it should filter the row

@humayunjaved-mz
Copy link

Hi i have integrated it but search is not giving results grid with paging toolbar but sakis grid example is working with pagingtoolbar could you please tell why it is so? i am using Extjs 4.1.1a. ??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment