Extjs - init class atttribute and get class name - extjs

i have simple 'gridpanel' with 'tbar' like this
Ext.define('Ext.abc.grid', {
extend: 'Ext.grid.Panel',
type:1,
tbar:[
{
text:'title1',
class :'a1',
handler:function(type){
if (this.type == 1) { // button not 1
Ext.query(".a2").setDisabled(false);
}
},{
text:'title2',
class :'a2',
handler:function(type){
if (this.type == 1) { // button not 1
Ext.query(".a1").setDisabled(false);
}
}
]
});
i try to add class (a1) to button title1 and the some for title2, but when i get class like
Ext.query(".a1").setDisabled(false);
it's not working
and i can't get type = 1 when i click title1, i using this.type but results is 'button' not 1
How can i do that, thanks

You've got several problems here.
First, see sha's answer, you're getting an array as the result of your call to Ext.query(...).
Second, Ext.query returns Ext.dom.Element, which are Ext objects for representing actual DOM elements like div, img, etc. What you want to access, your buttons, are Ext.Component. You can query components with Ext.ComponentQuery.
Then, you're using this.type in your button handler functions, but when these method get called, this will be the button itself (this can be customized using the scope option), not the container on which you set type: 1.
Edit:
Here's how to make your example work:
Ext.define('Ext.abc.Grid', {
extend: 'Ext.grid.Panel'
,type: 1
,tbar: [{
text: 'title1'
,itemId: 'button1'
// just FYI, here the scope (this) is the window, because we are not
// in a method
,scope: this // so this doesn't work
,handler: function() {
// using ComponentQuery to get a reference to the other components
var grid = this.up('grid'), // by xtype
tbar = this.up(), // by relative position
button2 = tbar.down('#button2'); // by itemId
if (grid.type === 1) {
button2.disable();
}
}
}, {
text: 'title2'
,itemId: 'button2'
,handler: function() { ... }
}]
});
Now, reading your mind, here's what I think you actually want to do:
Ext.define('Ext.abc.Grid', {
extend: 'Ext.grid.Panel'
,type: 1
,tbar: [{
text: 'title1'
,itemId: 'button1'
}, {
text: 'title2'
,itemId: 'button2'
}]
// reading in your mind, I guess, this is what you really want to do:
,initComponent: function() {
this.callParent();
if (this.type === 1) {
this.down('#button2').disable();
} else {
this.down('#button1').disable();
}
}
});

Ext.query returns you an array http://docs.sencha.com/extjs/4.1.3/#!/api/Ext-method-query
You can't simply call setDisabled() on an array. You need to loop through all elements.

Related

ExtJS5 Store filter "Uncaught TypeError: Cannot read property 'get' of undefined"

I'm using the gpl version of extjs5.1.1 without sencha cmd.
In my application a Grid displays correctly a Store.
In the window, there is a checkbox wich code is :
{
xtype : 'checkbox',
itemId : 'employeeFilter',
value : false,
boxLabel : 'Show inaktiv users',
margin : '0 5 0 5',
listeners: {
change: function(checkbox, newValue, oldValue, eOpts) {
var store = this.up('window').getComponent('employeeGrid').getStore();
if (newValue) {
console.log('clearFilter');
store.clearFilter();
} else {
console.log('rightFilter');
store.rightFilter();
}
}
}
}]
The variable store points to the grid store correctly. I can see the messages 'clearFilter' and 'rightFilter' in the console.
The store code:
Ext.define('Chronos.store.manage.Employees', {
extend : 'Ext.data.Store',
model : 'Chronos.model.manage.Employee',
autoLoad : false,
autoSync : true,
sortOnLoad : false,
pageSize : 0,
rightFilter: function() {
this.filterBy(function(record) {
return record.get('rights') >= 0;
});
},
proxy : {
type : 'ajax', // Ext.data.proxy.Ajax
api : {
create : 'api/management/employees.create.php',
read : 'api/management/employees.read.php',
update : 'api/management/employees.update.php',
destroy : 'api/management/employees.destroy.php'
},
reader : {
type : 'json', // Ext.data.reader.Json
rootProperty : 'records'
},
writer : {
type : 'json', // Ext.data.writer.Json
encode : true,
rootProperty : 'record'
}
}
});
On window call, the checkbox is unchecked and the filter is active because the grid listeners is:
listeners: {
render: function() {
this.getStore().load();
this.getStore().rightFilter(); // <<<<< if the function is called here, the problem exists, if not, the filter works perfectly !
}
},
The first time I check the checkbox the filter is cleared correctly and the message 'clearFilter' appears in the console. When I uncheck it, the message 'rightFilter' appears too, but the filter does not anything in the grid... and the error message "Uncaught TypeError: Cannot read property 'get' of undefined" appears.
Where am I wrong?
Edit: Actually the filter function only works fine once. It does not work any more after clearFilter is called...
I tried with addFilter/removeFilter with the same result.
My next try will be setDisable.
If someone has any (other) idea...
Edit 2: Test case in fiddle
Now I know that the problem comes from function call in the render function. When this call is not done, the checkbox works perfectly, but on show, the checkbox state does not correspond to the display and I want to hide filtered items on show.
Any Idea ?
The filter function cannot be called just after the load, that's why load in render and filter in viewready (in afterrender it doesn't work either). The problem is solved !!
listeners: {
render: function() {
this.getStore().load();
},
viewready: function() {
this.getStore().rightFilter();
}
}
The problem is in this line is with this.
rightFilter: function() {
this.filterBy(function(record) { // <<<<< this line sends an error the second time the function is called
return record.get('rights') >= 0;
});
},
Can you please change the above code to
rightFilter: function(me) {
me.filterBy(function(record) { // <<<<< this line sends an error the second time the function is called
return record.get('rights') >= 0;
});
},
and the grid listener to pass store
listeners: {
render: function() {
this.getStore().load();
this.getStore().rightFilter(this.getStore());
}
},
and the calling from combobox to
if (newValue) {
console.log('clearFilter');
store.clearFilter();
} else {
console.log('rightFilter');
store.rightFilter(store);
}

Sencha Touch 2.3: Remove validations from hidden form fields

I am doing form validations in Sencha Touch 2.3. My model looks like following.
Ext.define('net.omobio.dialog.dialogcc.model.StockTransferDetails', {
extend: 'Ext.data.Model',
config: {
fields: ['to_msisdn','to_profile_id','transfer_lob','transfer_item_status','transfer_product','transfer_qty','transfer_req_type','transfer_item_type','transfer_pack_type'],
validations: [
{ type: 'presence', field: 'to_msisdn' },
{ type: 'presence', field: 'to_profile_id' },
{ type: 'exclusion', field: 'transfer_lob', list: ['null'] },
{ type: 'exclusion', field: 'transfer_req_type', list: ['null'] },
{ type: 'exclusion', field: 'transfer_item_type', list: ['null'] },
{ type: 'exclusion', field: 'transfer_pack_type', list: ['null'] }
]
}
});
Following is a code segment that I use in my controller to remove validations from hidden form fields but no luck.
var form1 = me.getStockTransferRequestPage();
var model = Ext.create("net.omobio.dialog.dialogcc.model.StockTransferDetails", form1.getValues());
// validate form fields
var errors = model.validate();
if (!errors.isValid()) {
// loop through validation errors and generate a message to the user
errors.each(function (errorObj){
//errorString += errorObj.getField() + " " + errorObj.getMessage();
console.log('7777777777777777777 '+errorObj.getField());
if (!Ext.getCmp(errorObj.getField().toString()).isHidden()) {
var s = Ext.String.format('field[name={0}]',errorObj.getField());
form1.down(s).addCls('invalidField');
}
});
Ext.Msg.alert('','stock_transfer.errors.required_fields_empty');
}
I would be much appreciated if anyone could help me to solve this.
Thank you
so there are multiple ways to achieve this, my preference even though some folks won't like it, but it will always work.
I did the following override to solve this problem, tried my best not to affect the normal flow of validation.the first two overrides have to be added somewhere to your overrides folder, you only have to add them once for the whole app.
Ext.Define('Ext.form.field.BaseOverride', {
override: 'Ext.form.field,Base',
/* traverse up and look for a hidden Parent/Ancestor */
isParentHidden: function () {
return this.up('[hidden=true]');
}
/* override isValid basic method to consider skipValidateWhenHidden property, when skipValidateWhenHidden is set to true code should check if the elementor it's Parent/Ancestors is hidden */
isValid: function () {
var me = this,
disabled = me.disabled,
isHidden = me.isHidden(),
skipValidateWhenHidden = !!me.skipValidateWhenHidden,
validate = me.forceValidation || !disabled,
isValid = validate ? me.validateValue(me.processRawValue(me.getRawValue())) : disabled;
if (isValid || !skipValidateWhenHidden) {
return isValid;
}
if (skipValidateWhenHidden) {
isHidden = isHidden ? true : me.isParentHidden();
if (isHidden) {
return skipValidateWhenHidden;
}
}
return isValid;
}
});
and eventually you'll be able to do the following, which is set the property to true on any field so if its not visible for the user, it will survive validation
{
itemId: 'City',
cls: 'AddressCity',
xtype: 'textfield',
emptyText: emptyCityText,
skipValidateWhenHidden: true,
},
another approach is to add a show()/Hide() listener on the fields container to enable/disable the children, disabling the fields would make them skip validation, but i'm not a big fan of managing button states and wiring listeners.
Note
Ext.getCmp() takes component id
errorObj.getField().toString() returns model field name, It won't
return id of the component (hidden) field.
So if model field name matches with hidden field id, It will work. Otherwise it won't work.

Prevent Rendering (hide and/or disable) of a Component at construction time

Background: Our app is always packed as a whole but through the users access some serverside actions may be restricted. We know which actions are allowed the time the app starts. We now want to hide all the views (panels, buttons, etc) from the user to which he lacks the access to.
For that we have written a plugin which can be applied to any Component. But here comes the problems:
Here is what we try to run against the plugin host:
if (cmp['setVisible']) cmp.setVisible(false); else cmp.hidden = true;
if (cmp['disable']) cmp.disable(); else cmp.disabled = true;
cmp.on('beforerender', function() { return false; })
First we thought the earlier we do this the better. So we tried to run it at construction time of the plugin. But that was not possible because the listeners (of the host) seems to be not ready yet (the component tries to fire the hide event). So we moved it into the init method of the plugin which does not throw a error but just worked partly. Only the beforerender event got really applied but it only aborted the rendering of the child. so we ended up with a broken looking component (the borders are there and the content not). If we commented the event registration out the host stayed untouched. We also tested the use of only the hidden:true and disabled:true with no luck.
So how can we prevent rendering of component in the correct way?
Edit:
The component should be flagged as disabled and hidden because we cannot prevent the creation of the component. The snipped I got from my colleague was wrong so the call of setVisible(false) worked, we guess disable() also. But the component get stilled rendered and we seem not really able to veto this without ending up with a half rendered component.
Answer by #AlexTokarev
I tried what #AlexTokarev suggested. For that I added the following lines into the Plugin-Constructor
cmp.hidden = true;
cmp.autoShow = false; // I know this may do nothing for non floating but I added it anyway
cmp.autoRender = true;
Based on debugging I know that the settings get applied really early (at the Ext.AbstractComponent.constructor), but I still ending up with a hidden and rendered component.
Comment by #sbgoran
In one Testcase we use a column-layout in which all containers extend from the same class. As soon as I add our plugin (with the beforerender event returning false configuration) to one of this extending containers (the plugin is directly added to class definition (as ptype)) all containers within this columns look broken (only borders are rendered and in the content a small grey box in the upper left corner.). So the aborted rendering affect all child items of the column when only one child item get the rendering canceled.
**Sample Code **
First I want to note that we are looking for a way to do this in general cause as far as we know the rendering in ExtJS is one thing. I can ask to setup a demo but I think this will not be that easy because we are using the Ext.app.portal.Panel for the failing example. but the plugin should work for any sort of Component. First I will add some demo code:
We have a view which is placed into a Viwport with border layout
Ext.define('MVC.view.Application',{
extend:'Ext.tab.Panel',
alias:'widget.appview',
region: 'center',
activeTab: 1
});
Within the Controller we fill this
var portal = this.portalRef = Ext.widget('portalpanel', {
title: 'Employee',
portalCols: 2
});
portal.addPortlet(0,['employee','employee2','employee3']);
portal.addPortlet(1,['employee4','employee5']);
app.appviewmain.add(portal);
Here is the portal panel
Ext.define('MVC.app.portal.PortalPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.portalpanel',
requires: [
'Ext.layout.container.Column',
'Ext.app.portal.PortalDropZone',
'Ext.app.portal.PortalColumn'
],
portalCols: 2,
portalColCfg: {
defaults: {
closable: false,
draggable: false,
collapsible: false,
header: false,
bodyStyle: {
background: '#fff',
padding: '10px'
}
},
items: []
},
addPortlet: function(idx, portlets) {
if (idx > this.portalCols || idx < 0)
return;
var portalCol = this.items.getAt(idx);
function insertPortlet(portlet) {
if (Ext.isString(portlet)) {
portlet = { xtype: portlet };
}
portalCol.add(portlet);
};
if (Ext.isArray(portlets)) {
var len = portlets.length,
i = 0;
for(;i<len;i++) {
insertPortlet(portlets[i]);
}
} else {
insertPortlet(portlets);
}
},
initPortal: function() {
var cfg = this.portalColCfg,
i = 0,
cols = [];
for (;i<this.portalCols;i++) {
cols.push(Ext.clone(cfg));
}
this.items = cols;
},
cls: 'x-portal',
bodyCls: 'x-portal-body',
defaultType: 'portalcolumn',
autoScroll: true,
manageHeight: false,
initComponent : function() {
var me = this;
// init only if nothing is defined
if (!me.items)
me.initPortal();
// Implement a Container beforeLayout call from the layout to this Container
me.layout = {
type : 'column'
};
me.callParent();
me.addEvents({
validatedrop: true,
beforedragover: true,
dragover: true,
beforedrop: true,
drop: true
});
},
// Set columnWidth, and set first and last column classes to allow exact CSS targeting.
beforeLayout: function() {
var items = this.layout.getLayoutItems(),
len = items.length,
firstAndLast = ['x-portal-column-first', 'x-portal-column-last'],
i, item, last;
for (i = 0; i < len; i++) {
item = items[i];
item.columnWidth = 1 / len;
last = (i == len-1);
if (!i) { // if (first)
if (last) {
item.addCls(firstAndLast);
} else {
item.addCls('x-portal-column-first');
item.removeCls('x-portal-column-last');
}
} else if (last) {
item.addCls('x-portal-column-last');
item.removeCls('x-portal-column-first');
} else {
item.removeCls(firstAndLast);
}
}
return this.callParent(arguments);
},
// private
initEvents : function(){
this.callParent();
this.dd = Ext.create('Ext.app.portal.PortalDropZone', this, this.dropConfig);
},
// private
beforeDestroy : function() {
if (this.dd) {
this.dd.unreg();
}
this.callParent();
}
});
And here is the Portlet
Ext.define('Ext.app.portal.Portlet', {
extend: 'Ext.panel.Panel',
alias: 'widget.portlet',
layout: 'fit',
anchor: '100%',
frame: true,
closable: true,
collapsible: true,
animCollapse: true,
draggable: {
moveOnDrag: false
},
cls: 'x-portlet',
initComponent : function() {
this.callParent();
},
// Override Panel's default doClose to provide a custom fade out effect
// when a portlet is removed from the portal
doClose: function() {
if (!this.closing) {
this.closing = true;
this.el.animate({
opacity: 0,
callback: function(){
var closeAction = this.closeAction;
this.closing = false;
this.fireEvent('close', this);
this[closeAction]();
if (closeAction == 'hide') {
this.el.setOpacity(1);
}
},
scope: this
});
}
}
});
Here is a sample view
Ext.define('MVC.view.employee.Employee',{
extend:'Ext.app.portal.Portlet',
alias:'widget.employee',
plugins: [{ptype: 'directbound', accessRoute: 'Employee.Read'}],
items: [
/*A form with some fields*/
]
});
Here's the plugin
Ext.define('MVC.direct.plugins.DirectBound',{
extend: 'Ext.AbstractPlugin',
alternateClassName: ['MVC.direct.DirectBound'],
alias: 'plugin.directbound',
/**
* #cfg {int} blockMode Indicates the way in which the Component gets blocked
* options
* 0 hide and disable
* 1 disable
*/
blockMode: 1,
constructor: function(config) {
var me = this,
cmp = config['cmp'],
route;
me.parseRoute(route);
// check for access
if (!me.checkAccess()) {
if (me.blockMode === 0) {
cmp.hidden = true;
cmp.autoShow = false;
cmp.autoRender = true;
}
me.diabled = true;
}
me.callParent(arguments);
}
/* some more methods */
});
Here's the column Layout
Ext.define('MVC.app.portal.PortalColumn', {
extend: 'Ext.container.Container',
alias: 'widget.portalcolumn',
requires: [
'Ext.layout.container.Anchor',
'MVC.app.portal.Portlet'
],
layout: 'anchor',
defaultType: 'portlet',
cls: 'x-portal-column'
// This is a class so that it could be easily extended
// if necessary to provide additional behavior.
});
Have you tried to set autoRender: true in your optional components? Here's the doc: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.AbstractComponent-cfg-autoRender
You can try with hide and show functions and also try with "added" event listener, which will be called after adding the component to container.
Try something like this for your plugin:
Ext.define('MVC.direct.plugins.DirectBound',{
extend: 'Ext.AbstractPlugin',
alternateClassName: ['MVC.direct.DirectBound'],
alias: 'plugin.directbound',
/**
* #cfg {int} blockMode Indicates the way in which the Component gets blocked
* options
* 0 hide and disable
* 1 disable
*/
blockMode: 1,
constructor: function(config) {
var me = this,
cmp = config['cmp'],
route;
me.parseRoute(route);
// Try to define beforerender callback on component and return false if
// component should not be visible
cmp.on('beforerender', function() {
if (!me.checkAccess()) {
if (me.blockMode === 0) {
return false;
}
// Not sure what this do for you but it wont disable component
// if you want your component disabled here try cmp.disable()
me.diabled = true;
}
});
// Maybe this code is not needed anymore
// check for access
if (!me.checkAccess()) {
if (me.blockMode === 0) {
cmp.hidden = true;
cmp.autoShow = false;
cmp.autoRender = true;
}
me.diabled = true;
}
// This should stay for sure
me.callParent(arguments);
}
/* some more methods */
});

Dynamically add xtype items to the panel with slidenavigatoin

So I'm trying to put items dynamically to the panel that has slidenavigation feature:
// FlyoutNavigation.js
Ext.define("APN.view.FlyoutNavigation", {
id: "flyoutNavigationPanel",
extend: 'Ext.ux.slidenavigation.View',
Here is the initialisation of the view in another view:
// MainViewContainer.js
this.home = "Some var"
this.flyout = Ext.create('APN.view.FlyoutNavigation', {
id: 'flyoutNavigationPanel',
home: this.home
});
Than I'm trying to use this variable in the this.config.items section, however that doesn't work, it seems that Sencha compiles everything first and than initialiases the components, I might be wrong, I'm really new to Sencha Framework.
So here is the view where the home variable is used:
Ext.define("APN.view.FlyoutNavigation", {
id: "flyoutNavigationPanel",
extend: 'Ext.ux.slidenavigation.View',
xtype: 'flyoutnavigation',
requires: [
... heaps of things omitted ...
],
initialize: function () {
this.callParent();
this.setupDynamicItems();
},
config: {
items: [
{
itemId: 'nav_home',
id: 'homeView',
items: [{
xtype: 'articlelist',
id: 'latestNews',
feedUrlName: this.home, // - that's the place where UNDEFINED occurs
flex: 1
}
],
},
So this.home is undefined...
One possible solution
Comming from this question: How to dynamically create xtype templates in Sencha Touch
I decided to put all the code in this.config.items.add({ ... my items ... }) however Ext.ux.slidenavigation.View looks like gave me the BUG! :( as the initialise method occurs after the binding methods on items of FlyoutNavigation view.
Here is the message from of the bug: Uncaught TypeError: Cannot read property 'raw' of undefined View.js:310 which is basically this line: if (Ext.isFunction(item.raw.handler)) {
So my questions would be
How to get the instance variable in the config.items section? If that's possible, than all is OK
Or do you know the work around of this issue?
Thanks
I don't think you can use this.config when defining the class, instead you can use initialize function as I told you earlier. So you should be able to do this:
initialize : function() {
var me = this;
var home = me.config.home;
me.add({
itemId: 'nav_home',
id: 'homeView',
items: [{
xtype: 'articlelist',
id: 'latestNews',
feedUrlName: home,
flex: 1
}
],
});
}
OR if you have defined homeView in parent class, you can do this:
initialize : function() {
var me = this;
var home = me.config.home;
me.down('#homeView').add({
xtype: 'articlelist',
id: 'latestNews',
feedUrlName: home,
flex: 1
});
}

Apply grid filter programmatically from function

Using Ext.ux.grid.FiltersFeature, I have remote filters and I am trying to write a function to apply a date filter on a grid column programmatically (rather than clicking on the filter drop down menu in the column header). The first time I run the function the grid store gets reloaded without the filter. When I run the function a second time (and every time thereafter) it works totally fine, the store reloads with the filters. Here is the gist of the function I have:
// a filter object for testing
aFilter = {type: 'date', field: 'a_date_field', comparison: 'gt', value: '2012-03-08 00:00:00'}
var grid = Ext.create('Ext.grid.Panel', {
store: store,
features: [{
ftype: 'filters',
}],
columns[{
header: 'ID',
dataIndex: 'id',
itemId: 'id',
width: 40,
}, {
xtype: 'datecolumn',
header: 'Date',
dataIndex: 'a_date_field',
itemId: 'a_date_field',
width: 75,
format:'j-M-Y',
filterable: true
}],
listeners: {
'afterrender': function() {
// Need to create the filters as soon as the grid renders
// rather than waiting for the user to click on the header
grid.filters.createFilters();
}
},
bbar: [{
text: 'Do a filter',
handler: function() {
// get the filter that is attached to the grid
var gridFilter = grid.filters.getFilter(aFilter.field);
// have to do this to create a menu for this filter
gridFilter.init({dataIndex: aFilter.field, type: aFilter.type, active: true});
// if this column is a date filter column
if (gridFilter.type == 'date') {
var dateValue = Ext.Date.parse(aFilter.value, 'Y-m-d H:i:s');
if (filter.comparison == 'gt') {
gridFilter.setValue({after: dateValue});
} else {
gridFilter.setValue({before: dateValue});
}
}
}
}
});
I also found that this function works the first time if I click on any grid header menu before I run the function.
I've been trying to find out what changes are made to the grid which make the filter work after the first attempt fails or what clicking on any grid header does to make it work. But nothing I add seems to fix it so it will run the first time. Has anyone implemented this successfully?
I have workaround:
bbar: [{
text: 'Do a filter',
handler: function() {
var grid = this.up('grid');
var dateValue = Ext.Date.parse(aFilter.value, 'Y-m-d H:i:s');
var value = aFilter.comparison == 'gt' ? {after: dateValue} : {before: dateValue};
var gridFilter = grid.filters.getFilter(aFilter.field);
if (!gridFilter) {
gridFilter = grid.filters.addFilter({
active: true,
type: aFilter.type,
dataIndex: aFilter.dataIndex,
});
gridFilter.menu.show();
gridFilter.setValue(value);
gridFilter.menu.hide();
} else {
gridFilter.setActive(true);
}
Ext.Function.defer(function(){
gridFilter = grid.filters.getFilter(aFilter.field);
gridFilter.setValue(value);
}, 10);
}
}]
As you can see I actually apply filter 2 times.
As an update, I expanded this function and modified it to work with ExtJS 4.1.1
Here is an example of the function to set grid filters dynamically (without the user needing to click on the menu items). Afterwards, the filtered items will be visible to the user in the grid column header menus as if he clicked on them and set them manually.
The "grid" argument is a grid with FiltersFeature that you want to filter. The other argument is an array of "filter" objects (I'll show an example below), the function simply applies all the passed "filter" objects to the grid.
doGridFilter: function(grid, filters) {
// for each filter object in the array
Ext.each(filters, function(filter) {
var gridFilter = grid.filters.getFilter(filter.field);
gridFilter.setActive(true);
switch(filter.data.type) {
case 'date':
var dateValue = Ext.Date.parse(filter.data.value, 'm/d/Y'),
value;
switch (filter.data.comparison) {
case 'gt' :
value = {after: dateValue};
break;
case 'lt' :
value = {before: dateValue};
break;
case 'eq' :
value = {on: dateValue};
break;
}
gridFilter = log.filters.getFilter(filter.field);
gridFilter.setValue(value);
gridFilter.setActive(true);
break;
case 'numeric':
var value;
switch (filter.data.comparison) {
case 'gt' :
value = {gt: filter.data.value};
break;
case 'lt' :
value = {lt: filter.data.value};
break;
case 'eq' :
value = {eq: filter.data.value};
break;
}
gridFilter = log.filters.getFilter(filter.field);
gridFilter.setValue(value);
gridFilter.setActive(true);
break;
case 'list':
gridFilter = log.filters.getFilter(filter.field);
gridFilter.menu.setSelected(gridFilter.menu.selected, false);
gridFilter.menu.setSelected(filter.data.value.split(','), true);
break;
default :
gridFilter = log.filters.getFilter(filter.field);
gridFilter.setValue(filter.data.value);
break;
}
});
}
Here's an example of a "filter" object array.
// an example of a "filters" argument
[{
field: 'some_list_column_data_index',
data: {
type: 'list',
value: 'item1,item2,item3,item4,item5,item6,item7'
}
}, {
field: 'some_date_column_data_index',
data: {
type: 'date',
comparison: 'gt',
value: '07/07/2007'
}
}]
One caveat, you need to "create" the filters manually before using this function. Normally FiltersFeature grid filters are "created" the first time a user clicks on one of them, that may not happen if the user just wants to apply one of these predefined filters.
That can be handled easily by including this afterrender listener in the gridpanel.
listeners: {
// must create the filters after grid is rendered
afterrender: function(grid) {
grid.filters.createFilters();
}
}
Just add
filter: true
to grid columns description like this:
me.columns = [
{header:"Name", dataIndex:"name", editor:"textfield", filter: true},
];
if you want to get the filter work after the first attempt, first instance create.
Here is something that may be worth looking into. It seems that the filters plugin is listening for menucreate event to initialize the filters. I wonder if menu create event is deferred until necessary and hence the filters don't get initialized?
/**
* #private Handle creation of the grid's header menu. Initializes the filters and listens
* for the menu being shown.
*/
onMenuCreate: function(headerCt, menu) {
var me = this;
me.createFilters(); //<------
menu.on('beforeshow', me.onMenuBeforeShow, me);
},
Do you want to apply grid filter or may be store.filter() capability would suit you better? In this case just filter the store, and grid will display filtered records.
I discovered another way to implement this. It appears that grid features are only bound to the grid after the grid is rendered. This means that any setup of the filter will not take effect until after the grid is rendered. The initial load of the store appears to be initiated before the grid is rendered.
I solved my problem by creating my store with a memory proxy containing no data.
me.store = Ext.create('Ext.data.Store', {
model: 'SummaryData',
data: [],
proxy: {
type: 'memory',
reader: 'array'
},
remoteSort: true,
remoteFilter: true
});
Then set up an afterrender handler on the grid to poke in the correct proxy and initiate a load of the store.
afterrender: function () {
var me = this;
me.store.setProxy({
type: 'ajax',
url : '/print_unallocated/change_site__data',
reader: {
type: 'json',
root: 'rows'
},
listeners: {
exception: function (proxy, response) {
Max.reportException(response);
}
}
});
me.filters.createFilters();
me.store.load();
},
In the source, you can see a comment related to this.
// Call getMenu() to ensure the menu is created, and so, also are the filters. We cannot call
// createFilters() withouth having a menu because it will cause in a recursion to applyState()
// that ends up to clear all the filter values. This is likely to happen when we reorder a column
// and then add a new filter before the menu is recreated.
me.view.headerCt.getMenu();
You can test whether the menu has been created before applying your filter. If it hasn't, do it yourself.
if(!grid.getView().headerCt.menu){
grid.getView().headerCt.getMenu();
}

Resources