I have already wrote how to implement paging toolbar with filtering feature. Here I will show how to implement filter in form of plugin to use it with any toolbar of the grid.
Of course your toolbar can already have other GUI elements so I have implemented it with support of the placeholders. In the following sample I have a grid reload button and two filter elements: menu button and filter text field will be place after it in between delimiters.
initComponent: function () {
this.items = [
this.getReloadButton(),
'-',
'**FILTER_SPLIT_BUTTON**',
'**FILTER_TEXT_FIELD**',
'-'
];
this.callParent();
},
And I am not forgetting the initialization of the plugin:
plugins: {
filterplugin: {
}
}
The plugin code:
Ext.define('App.ux.grid.toolbar.plugin.Filter', {
extend: 'Ext.plugin.Abstract',
alias: 'plugin.filterplugin',
filterItemWidth: 100,
filterOnType: true,
filterSplitButtonGlyph: 'xf0b0@FontAwesome',
filterSplitButtonText: "Filter",
filterSplitButtonPlaceHolder: '**FILTER_SPLIT_BUTTON**',
filterTextFieldPlaceHolder: '**FILTER_TEXT_FIELD**',
init: function (toolbar) {
this.placeFields();
toolbar.on('afterrender', this.updateSearchColumnsMenu, this);
},
placeFields: function () {
this.replacePlaceHolderByCmp(
this.filterSplitButtonPlaceHolder,
this.getFilterSplitButton()
);
this.replacePlaceHolderByCmp(
this.filterTextFieldPlaceHolder,
this.getFilterTextField()
);
},
replacePlaceHolderByCmp: function (placeHolder, cmp) {
var placeHolderIndex = this.getIndexByPlaceHolder(placeHolder),
placeHolderCmp = this.getPlaceHolderCmp(placeHolder);
this.getCmp().remove(placeHolderCmp);
this.getCmp().insert(placeHolderIndex, cmp);
},
getIndexByPlaceHolder: function (placeHolder) {
return this.getCmp().items.findIndex('text', placeHolder);
},
getPlaceHolderCmp: function (placeHolder) {
var cmp = this.getCmp().down('[text="' + placeHolder + '"]');
return cmp;
},
getFilterSplitButton: function () {
if (!this.filterSplitButton) {
this.filterSplitButton = Ext.create('Ext.button.Split', {
text: this.filterSplitButtonText,
handler: this.doFilter,
glyph: this.filterSplitButtonGlyph,
scope: this
});
}
return this.filterSplitButton;
},
getFilterTextField: function () {
if (!this.filterTextField) {
this.filterTextField = Ext.create('Ext.form.field.Text', {
submitValue: false,
isFormField: false,
width: this.filterItemWidth,
margin: '-1 2 3 2',
enableKeyEvents: true
});
if (this.filterOnType) {
this.filterTextField.on('change', this.doFilter, this);
} else {
this.filterTextField.on('specialkey', function () {
if (e.getKey() == e.ENTER) {
this.doFilter();
}
}, this);
}
}
return this.filterTextField;
},
getSelectAllColumnsMenuItem: function () {
if (!this.selectAllColumnsMenuItem) {
this.selectAllColumnsMenuItem = Ext.create('Ext.menu.CheckItem', {
text: "All Columns",
checked: true,
listeners: {
checkchange: {
fn: function (menuCheckItem, checked) {
this.getFilterColumnsMenu().items.each(function (item) {
if (item.dataIndex) {
item.setChecked(checked);
}
});
this.doFilter();
},
scope: this
}
}
});
}
return this.selectAllColumnsMenuItem;
},
getFilterColumnsMenu: function () {
if (!this.filterColumnsMenu) {
this.filterColumnsMenu = Ext.create('Ext.menu.Menu', {
items: [
this.getSelectAllColumnsMenuItem(), {
xtype: 'menuseparator'
}
]
});
}
return this.filterColumnsMenu;
},
updateSearchColumnsMenu: function () {
var columns = this.getCmp().up('grid').getColumns();
Ext.Array.each(columns, function (column) {
this.getFilterColumnsMenu().add({
xtype: 'menucheckitem',
text: column.text,
dataIndex: column.dataIndex,
checked: true,
listeners: {
checkchange: {
fn: function (menuCheckItem, checked) {
if (checked) {
var selectAllColumnsMenuItemCheck = true;
this.getFilterColumnsMenu().items.each(function (item) {
if (item.dataIndex && item.checked == false) {
selectAllColumnsMenuItemCheck = false;
return false;
}
});
this.getSelectAllColumnsMenuItem().setChecked(selectAllColumnsMenuItemCheck, true);
} else {
this.getSelectAllColumnsMenuItem().setChecked(false, true);
}
this.doFilter();
},
scope: this
}
}
});
}, this);
this.getFilterSplitButton().setMenu(this.getFilterColumnsMenu());
},
doFilter: function () {
var searchColumnIndexes = [],
searchValue = this.getFilterTextField().getValue();;
this.getFilterSplitButton().getMenu().items.each(function (item) {
if (item.dataIndex && item.checked) {
searchColumnIndexes.push(item.dataIndex);
}
}, this);
if (this.getStore().remoteFilter) {
this.remoteFilter(searchColumnIndexes, searchValue)
} else {
this.localFilter(searchColumnIndexes, searchValue);
}
},
localFilter: function (searchColumnIndexes, searchValue) {
this.getStore().removeFilter(this.filter);
this.filter = new Ext.util.Filter({
filterFn: function (record) {
if (searchColumnIndexes.length === 0 || Ext.isEmpty(searchValue)) {
return true;
}
var found = false;
Ext.Array.each(searchColumnIndexes, function (dataIndex) {
if (record.get(dataIndex) && record.get(dataIndex).indexOf(searchValue) != -1) {
found = true;
return false;
}
}, this);
return found;
}
});
this.getStore().addFilter(this.filter);
},
remoteFilter: function (searchColumnIndexes, searchValue) {
var remoteFilters = [];
Ext.Array.each(searchColumnIndexes, function (columnIndex) {
remoteFilters.push({
property: columnIndex,
value: searchValue
});
});
this.getStore().clearFilter();
this.getStore().filter(remoteFilters);
},
getStore: function () {
if (!this.store) {
this.store = this.getCmp().up('grid').getStore();
}
return this.store;
}
});