i just start to dive in ExtJS Grid, I would like create some toolbar search like JqGrid below. Grid will show the result according to key typed in that column.
Can anyone show me the walkthrough ? ^_^
Thanks in advance for any answers.
jqgrid http://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-ash4/379109_10150531271858928_704228927_8868872_1607857946_n.jpg
The way I do it is I add a top toolbar to the gridpanel which contains searchfields. Then it's just the matter of hooking up events to callbacks.
Below is an example for ExtJS 3.x. It's edited out code from my project, so I might have cut out too much, or left something that's not needed. See buildTBar(), buildSearchBar() and attachListeners() methods in particular.
Ext.ns('MyNs');
MyNs.GridPanel = Ext.extend(Ext.grid.GridPanel,{
initComponent: function() {
this.colModel = this.buildColModel();
this.store = this.buildStore();
this.tbar = this.buildTBar();
MyNs.GridPanel.superclass.initComponent.call(this);
this.attachListeners();
},
attachListeners: function() {
this.on('render', function() {
this.getPagingBar().bindStore(this.getStore());
this.getSearchBar().bindStore(this.getStore());
});
//I use this grid in a tab, so I defer loading until tab is activated
this.on('activate',function() {
var store = this.getStore();
if(store.getCount() == 0) {
store.load({
params: {
start: 0,
limit: 20
}
})
}
});
},
buildColModel: function() {
return new Ext.grid.ColumnModel({
columns: [
{header: 'Index', dataIndex: 'index'}
]
})
},
buildStore: function() {
//return a store
},
buildTBar: function() {
var items = new Array(
this.buildPagingBar(),
this.buildSearchBar()
)
return {
xtype: 'panel',
items: items
}
},
buildPagingBar: function() {
return {
xtype: 'paging',
pageSize: 20,
displayInfo: true,
displayMsg: 'Records{0} - {1} z {2}',
}
},
buildSearchBar: function() {
return {
xtype: 'toolbar',
itemId: 'searchBar',
items: [
{xtype: 'textfield', itemId: 'index'},
],
bindStore: function(store) { //here we bind grid's store to searchbar
this.store = store;
var me = this;
store.on('beforeload', function(store, options) {
options.params.index = me.find('itemId','index')[0].getValue();
})
Ext.each(this.findByType('textfield'),function(field) { //let's have store reloaded on field changes
field.on('change', function(field, newValue, oldValue) {
store.reload();
})
})
}
}
},
getPagingBar: function() {
return this.getTopToolbar().findByType('paging')[0];
},
getSearchBar: function() {
return this.getTopToolbar().find('itemId','searchBar')[0];
}
});
Related
I am trying to get the number of items in the combo box so that I can make the first value by default visible in the combo box using the getCount() method but I see it always return 0 so cannot get the first item to be displayed in the combo box.
Code for my combo box is as shown below:
Ext.define('something....', {
controller: 'some Controller',
initComponent: function() {
var me,
me = this;
me.items = [{
xtype: 'form',
items: [{
xtype: 'combo',
itemId: 'nameId',
name:'nameId',
labelAlign: 'top',
fieldLabel: 'Name',
store: me._getNames(),
//disabled:some condition?true:false,//doesn't gray out combo
valueField:'dataId',
displayField: 'firstName',
editable: false,
listeners:{
afterrender: function(combo,component) {
var combo = me.down('#nameId');
var nameStore = combo.getStore();
var setFirstRecord = function(combo){
var nameStore = combo.getStore();
if(nameStore.getCount() === 1){
combo.setValue(nameStore.getAt(0));
}
}
if(nameStore.isLoaded() === false){
nameStore.on('load', function(nameStore){
setFirstRecord(combo);
},this,{
single:true
});
}else{
setFirstRecord(nameStore);
}
},
}
}]
}];
}
Code for the store is as below:
_getNames: function (){
var nameStore = Ext.create('Ext.data.Store', {
autoLoad: true,
proxy: {
type: 'ajax',
url: 'name.json',
reader: {
type: 'json',
rootProperty:'items',
transform: function (data) {
var data = {
items: [{
dataId: data[0].dataId,
firstName: data[0].name.firstName,
nameDetails: data[0].nameDetails
}]
}
return data;
}
},
},
fields: ['dataId', 'firstName','nameDetails']
});
return namesStore;
}
})
The result returned from the api to populate the store is as follows:
[
{
"dataId":1,
"name":{
"dataId":1,
"firstName":"Julie",
"code":"10",
"connectionList":[
"EMAIL"
]
},
"nameDetails":{
"EMAIL":{
"dataId":1,
"detail":"EMAIL"
}
}
}
]
Any suggestions on what's missing would be great!
I am written that example for you in Sencha Fiddle: https://fiddle.sencha.com/#view/editor&fiddle/3cdl
That solve your problem:
combo.getStore().on("load",
function (store, records, successful, operation, eOpts) {
if (store.getData().length > 0)
combo.setValue(store.getData().get(0).getData().id)
},
this
)
You must check if store is loaded or not and write appropriate code:
...
...
xtype: 'combo',
itemId: 'nameId',
name: 'nameId',
labelAlign: 'top',
fieldLabel: 'Name',
store: this._getNames(),
valueField: 'dataId',
displayField: 'firstName',
editable: false,
listeners: {
afterrender: function (combo) {
var store = combo.getStore();
var setFirstRecord = function (combo) {
var store = combo.getStore();
if (store.getCount() === 1) {
combo.setValue(store.getAt(0));
}
}
if (store.isLoaded() === false) {
store.on('load', function (store) {
setFirstRecord(combo);
}, this, {
single: true
});
} else {
setFirstRecord(combo);
}
}
}
...
...
I want to filter my grid with different buttons that active certain filters. However they do not work on page load. Only when you select/deselect a filter option and then click the button, does the filter actually kick in.
When the page first loads and you click a button, you get the following error:
TypeError: filter is undefined
How do I enable these filter settings when the page first loads?
To recreate the error. Load the fiddle and try clicking the buttons and notice they don't work. Then activate one of the filters and try again. The buttons will work after a filter is activated.
Fiddle
Buttons
var openButton = Ext.create('Ext.Button', {
text: 'Open Topics',
handler: function () {
var filter = grid[uniqueId].filters.getFilter('TopicStateValue');
filter.setActive(true);
filter.setValue('Open/Current');
}
});
var holdButton = Ext.create('Ext.Button', {
text: 'On Hold Topics',
handler: function () {
var filter = grid[uniqueId].filters.getFilter('TopicStateValue');
filter.setActive(true);
filter.setValue('Hold');
}
});
var closedButton = Ext.create('Ext.Button', {
text: 'Closed Topics',
handler: function () {
var filter = grid[uniqueId].filters.getFilter('TopicStateValue');
filter.setActive(true);
filter.setValue('Archived/Closed');
}
});
Columns
columns: [{
text: 'Title',
width: 260,
dataIndex: 'Title',
filterable: true,
filter: {
type: 'string'
// specify disabled to disable the filter menu
//, disabled: true
}
}, {
text: 'Description',
flex: 1,
dataIndex: 'Description',
filter: {
type: 'string'
// specify disabled to disable the filter menu
//, disabled: true
}
}, {
text: 'Modified',
width: 90,
dataIndex: 'Modified',
xtype: 'datecolumn',
format: 'm/d/Y',
filter: true
}, {
text: 'Status',
width: 100,
dataIndex: 'TopicStateValue',
filter: {
active: true,
type: 'list',
value: 'Open/Current',
options: ['Open/Current', 'Archived/Closed', 'Hold']
}
}]
Just check if the filter exists before pass value to it, if not, add it like this:
var openButton = Ext.create('Ext.Button', {
text: 'Open Topics',
handler: function () {
var filter = grid[uniqueId].filters.getFilter('TopicStateValue');
if (!filter) {
filter = grid[uniqueId].filters
.addFilter({
type : 'string',
dataIndex : 'TopicStateValue'
});
}
filter.setActive(true);
filter.setValue('Open/Current');
}
});
var holdButton = Ext.create('Ext.Button', {
text: 'On Hold Topics',
handler: function () {
var filter = grid[uniqueId].filters.getFilter('TopicStateValue');
if (!filter) {
filter = grid[uniqueId].filters
.addFilter({
type : 'string',
dataIndex : 'TopicStateValue'
});
}
filter.setActive(true);
filter.setValue('Hold');
}
});
var closedButton = Ext.create('Ext.Button', {
text: 'Closed Topics',
handler: function () {
var filter = grid[uniqueId].filters.getFilter('TopicStateValue');
if (!filter) {
filter = grid[uniqueId].filters
.addFilter({
type : 'string',
dataIndex : 'TopicStateValue'
});
}
filter.setActive(true);
filter.setValue('Archived/Closed');
}
});
You need to initialize the filters manually before you use them.
Please add the below code to your grid panel.
listeners: {
beforeRender:function() {
this.filters.createFilters();
}
},
I tried that on your fiddle and it works.
I am starting to look at how I would get my grid edits back to a service via the datasource.
Following the documentation, I have set a local test data source as follows..
function getDataSource() {
var gridData = [
{
col1: new CellData('1', 'data1-1'),
col2: new CellData('2', 'data1-2')
},
{
col1: new CellData('3', 'data2-1'),
col2: new CellData('4', 'data2-2')
},
];
var dataSrc = new kendo.data.DataSource({
batch: true,
transport: {
read: function (e) {
e.success(gridData);
},
update: function (e) {
// batch is enabled
var updateItems = e.data.models;
// This is not called
// on success
e.success();
},
create: function (e) {
e.success(e.data);
},
destroy: function (e) {
e.success();
}
}
});
return dataSrc;
}
I have a toolbar setup (with the "Save Changes"), and this is calling the SaveChanges configuration event, how ever, just cannot see what else I need to do to get the following to occur..
Have the data sources update called
Mark the grid "on dirty" so that the red "edited" indicators on the edited cells disappear
I am having the same problem with the Add New record (though I can't get the grids "addRow" even to fire here)
I have the running example here
Any help would be great appreciated!
You need to specify the DataSource schema for this to work:
var dataSrc = new kendo.data.DataSource({
batch: false, // true would mean transport functions get multipe models in e.data
transport: {
// ....
},
schema: {
data: function (response) {
return response;
},
model: {
id: "id",
fields: {
id: {
editable: false,
defaultValue: 0 // 0 == new / unsaved row
},
col1: {
editable: true,
// new items would have that using default add button
defaultValue: {
id: 0,
CategoryName: ""
},
fields: { id: { editable: true }, display: { editable: true }
},
col2: {
editable: true,
fields: { id: { editable: true }, display: { editable: true } }
}
}
}
}
});
Also note:
grid.saveChanges will sync the DS, so you don't need to do anything in the event
There is no addRow event.
The default "create" button will try to add an empty object; since you work with nested objects, you need to add the row yourself so you can initialize the properties; thus you need a custom button and bind your action manually
(demo)
I am trying to hide the column if all the cells in the column are empty. I am trying to do this in the column listener by iterating through the store but I guess the store isnt populated at that time. any suggestions to achieve this functionality?
Ext.define('com.abc.MyGrid' , {
extend: 'Ext.grid.Panel',
store : 'MyStore',
columns : [{
text : 'col1',
sortable : true,
dataIndex : 'col1'
}, {
text : 'col2 ',
sortable : true,
dataIndex : 'col2',
listeners:{
"beforerender": function(){
console.log(this.up('grid').store);
this.up('grid').store.each(function(record,idx){
// if all are null for record.get('col1')
// hide the column
console.log(record.get('col1'));
});
}
}
}
})
But this is isnt working. Basically the store loop in the column listener "before render" is not executing where as the above console(this.up('grid').store) prints the store with values.
Here you go, it doesn't handle everything but should be sufficient.
Ext.define('HideColumnIfEmpty', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.hideColumnIfEmpty',
mixins: {
bindable: 'Ext.util.Bindable'
},
init: function(grid) {
this.grid = grid;
this._initStates();
this.grid.on('reconfigure', this._initStates, this);
},
_initStates: function(store, columns) {
var store = this.grid.getStore(),
columns = this.grid.columns;
this.bindStore(store);
this.columns = columns;
if(store.getCount() > 0) {
this._maybeHideColumns();
}
},
/**
*#implement
*/
getStoreListeners: function() {
return {
load: this._maybeHideColumns
};
},
_maybeHideColumns: function() {
var columns = this.columns,
store = this.store,
columnKeysMc = new Ext.util.MixedCollection();
Ext.Array.forEach(columns, function(column) {
columnKeysMc.add(column.dataIndex, column);
});
Ext.Array.some(store.getRange(),function(record){
//don't saw off the branch you are sitting on
//eachKey does not clone
var keysToRemove = [];
columnKeysMc.eachKey(function(key) {
if(!Ext.isEmpty(record.get(key))) {
keysToRemove.push(key);
}
});
Ext.Array.forEach(keysToRemove, function(k) {
columnKeysMc.removeAtKey(k);
});
return columnKeysMc.getCount() === 0;
});
columnKeysMc.each(function(column) {
column.hide();
});
}
});
Here is an example:
Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['name', 'email', 'phone'],
data:{'items':[
{ 'name': 'Lisa', "email":"lisa#simpsons.com", "phone":"555-111-1224" },
{ 'name': 'Bart', "email":"bart#simpsons.com", "phone":"555-222-1234" },
{ 'name': 'Homer', "email":"home#simpsons.com", "phone":"555-222-1244" },
{ 'name': 'Marge', "email":"marge#simpsons.com", "phone":"555-222-1254" }
]},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}
});
Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: Ext.data.StoreManager.lookup('simpsonsStore'),
columns: [
{ text: 'Name', dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email', flex: 1 },
{ text: 'Phone', dataIndex: 'phone' },
{ text: 'Says Doh', dataIndex: 'saysDoh'}
],
plugins: {ptype: 'hideColumnIfEmpty'},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
You can see in the example that saysDoh column is hidden.
If you want to iterate over the store, you need to put a listener on the load event of your store. The beforerender doesn't mean that your store is already loaded.
I would put the creation of you store in the initComponent. Something like this:
Ext.define('com.abc.MyGrid', {
extend: 'Ext.grid.Panel',
columns: [{
text: 'col1',
sortable: true,
dataIndex: 'col1'
}, {
text: 'col2 ',
sortable: true,
dataIndex: 'col2'
},
initComponent: function () {
var me = this;
//Create store
var myStore = Ext.create('MyStore');
myStore.load(); // You can remove this if autoLoad: true on your store.
//Listen to load event (fires when loading has completed)
myStore.on({
load: function (store, records, success) {
store.each(function (record, idx) {
console.log(record.get('col1'));
});
}
});
//Apply the store to your grid
Ext.apply(me, {
store: myStore
});
me.callParent();
}
});
I'm using GeoExt2 (alpha) + Extjs 4.1 now to implement a map application. The thing is sometimes when I select a feature on the map, two popups are displayed. one at the bottom of the screen which has correct info and one empty in the right place. it doesn't go even I close it. I wonder if this is a bug ?
myLayer.events.on({
featureselected: function(e) {
createPopup(e.feature);
},
featureunselected: function(){
popup.destroy();
}
});
function createPopup(feature) {
popup = Ext.create('GeoExt.Popup', {
id: 'popup',
title: title,
location: feature,
});
popup.on({
close: function() {
if(OpenLayers.Util.indexOf(myLayer.selectedFeatures,
this.feature) > -1) {
selectControl.unselect(this.feature);
}
}
});
PopupTab = Ext.create('Ext.tab.Panel', {
id: 'PopupTabs',
activeTab:2,
items: [
{
title: 'Supervisor',
itemId: 'tab1',
},
{
title: 'student',
itemId: 'tab2',
items: [
{
xtype: 'label',
id: 't',
html: content,
layout: 'fit',
cls:'tabStyle'
}
]
},
],
listeners: {
tabchange: function(panel, tab) {
if (tab.popup !== undefined) { // show window after tab change
tab.popup.show();
}
}
}
});
popup.add(PopupTabs);
popup.show();
}