ExtJs: Store populated by Grid comes up as blank - extjs

I am using an ArrayStore and filling it up by adding model records.
This store is associated with a data grid.
Now the arraystore object is getting filled perfectly fine but the data is not coming up in the grid. In fact, on debugging, I found that the store of the grid (datagrid.store) also has the data, but still it does not display it on the screen!!
Following is my code.
Model:
Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLAttributeValueModel', {
extend: 'Ext.data.Model',
fields: [
{
name: 'attribute',
type: 'string'
},
{ name: 'attributeValue',
type: 'string'
}
]
});
Store:
var attrValueStore = Ext.create('Ext.data.ArrayStore', {
autoSync: true,
model: 'Ext.ux.window.visualsqlquerybuilder.SQLAttributeValueModel'
});
Grid
Ext.define('Ext.ux.window.visualsqlquerybuilder.SQLAttributeValueGrid', {
//requires: ['Ext.ux.CheckColumn'],
autoRender: true,
extend: 'Ext.grid.Panel',
alias: ['widget.attributevaluegrid'],
id: 'SQLAttributeValueGrid',
store: attrValueStore,
columnLines: true,
plugins: [Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})],
columns: [
{ /*Expression */
xtype: 'gridcolumn',
text: 'Attribute',
sortable: false,
menuDisabled: true,
flex: 0.225,
dataIndex: 'attribute'
},
{ /*Attribute Values*/
xtype: 'gridcolumn',
editor: 'textfield',
text: 'Values',
flex: 0.225,
dataIndex: 'attributeValue'
}
],
initComponent: function () {
this.callParent(arguments);
}
});
Modal Window displaying the grid
var attributeValueForm = Ext.create('Ext.window.Window', {
title:'Missing Attribute Values',
id: 'attributeValueForm',
height:500,
width:400,
modal:true,
renderTo: Ext.getBody(),
closeAction: 'hide',
items:[
{
xtype: 'attributevaluegrid',
border: false,
//height: 80,
region: 'center',
split: true
}
],
buttons: [
{
id: 'OKBtn',
itemId: 'OKBtn',
text: 'OK',
handler: function () {
Ext.getCmp('attributeValueForm').close();
}
},
{
text: 'Cancel',
handler: function () {
Ext.getCmp('attributeValueForm').close();
}
}
]
});
Now at the time of displaying the modal window, I checked the value of the store object as well as the store inside the grid object. Both are having the proper data.
But when the window opens, I am getting a blank grid

Maybe you need to load the store data... try with:
var attrValueStore = Ext.create('Ext.data.ArrayStore', {
autoSync: true,
autoLoad : true,
model: 'Ext.ux.window.visualsqlquerybuilder.SQLAttributeValueModel'
});

Related

How to make an Extjs4.2 Chart filtered by a list

I'm pretty new to web development and ExtJS, I've looked around for tutorials on more complex concepts but they are hard to find (Yes I've found the Sencha documentation but the only provide simple concepts)
I'm trying to make a dashboard for my application, in this dashboard I want a chart
that gives a detailed overview of my statistics. In order to accomplish this I am trying to add a custom filter for the chart by making a seperate list with that holds all the instances of the key, when selecting said instances from a list I want the chart to only display those selected instances.
The chart I made:
Ext.define('view.chart.LocationStatisticsPerMonth', {
extend: 'Ext.chart.Chart',
alias: 'widget.LocationStatisticsPerMonthChart',
requires: [
'store.LocationStatisticsStore',
'store.TemplateStore',
'view.TitleToolbar'
],
constructor: function () {
this.store = Ext.create('store.LocationStatisticsStore', {
autoLoad: true, sorters: [{
property: 'YearMonth',
direction: 'ASC'
}]
});
this.store.getProxy().api.read = ServerControllers.Dashboard.LocationStatisticsPerMonth;
this.callParent(arguments);
},
animate: true,
shadow: true,
border: true,
legend: {
position: 'right'
},
axes: [{
type: 'Numeric',
position: 'left',
fields: ['TotalCount'],
title: false,
grid: true,
label: {
renderer: function (v) {
return String(v);
}
}
}, {
type: 'Category',
position: 'bottom',
fields: ['Location_Id'],
title: false,
label: {
rotate: {
degrees: 315
}
}
}],
series: [{
type: 'column',
axis: 'left',
gutter: 80,
xField: ['Location_Id'],
yField: ['TotalCount'],
tips: {
trackMouse: true,
width: 125,
height: 28,
renderer: function(storeItem, item) {
this.setTitle(String('Visitors: '+item.value[1]));
}
}
}]
});
My Store
Ext.define('store.LocationStatisticsStore', {
extend: 'Ext.data.Store',
requires: ['model.LocationStatistics'],
model: 'model.LocationStatistics',
autoLoad: false,
remoteSort: false,
remoteFilter: false,
filterOnLoad: true,
sorters: [{
property: ['YearMonth' , 'Location_Id'],
direction: 'DESC'
}],
proxy: {
type: 'direct',
paramOrder: [],
api: {
read: ServerControllers.Reports.GetLocationStatisticsPerMonth
},
reader: {
type: 'json',
root: 'data',
totalProperty: 'totalRecords',
successProperty: 'success',
messageProperty: 'msg'
}
}
});
My Model:
Ext.define('model.LocationStatistics', {
extend: 'Ext.data.Model',
idProperty: ['Location_Id'],
fields: [
{ name: 'YearMonth', type: 'string' },
{ name: 'Location_Id', type: 'int' },
{ name: 'Year', type: 'int' },
{ name: 'Month', type: 'int' },
{ name: 'TotalCount', type: 'int' },
{ name: 'AverageCountPerDay', type: 'int' }
]
});
Would anyone be so kind as to explain this concept to me, link a tutorial or provide me an example of how to go about doing this?
Help is greatly appreciated.
EDIT: the panel that this is contained in:
Ext.define('view.panel.DashboardStatisticsPanel', {
extend : 'Ext.panel.Panel',
alias : 'widget.DashboardStatisticsPanel',
requires : [
'Ext.layout.container.Column',
'view.chart.LocationStatisticsPerMonth'
],
plain: true,
border: false,
layout: {
type: 'hbox',
padding: '10 10 10 10'
},
items: [{
xtype: 'panel',
layout: 'fit',
border: true,
flex: 1,
items: [{
xtype: 'panel',
layout: 'anchor',
border: true,
overflowX: 'scroll',
height: 400,
dockedItems: [{
xtype: 'toolbar',
dock: 'top',
items: [{
xtype: 'label',
text: 'Select Date',
padding: '0 0 0 10'
},
{
xtype: 'combobox',
displayField: 'YearMonth',
emptyText: 'Select Date ',
queryMode: 'local',
padding: '0 0 0 10',
store: function (btn) {
btn.up('panel').down('LocationStatisticsPerMonthChart').getStore();
},
valueField: 'YearMonth',
}]
}]
/*tbar: [{
text: 'September Only',
handler: function (btn) {
var store = btn.up('panel').down('LocationStatisticsPerMonthChart').getStore();
store.clearFilter();
Ext.defer(function (btn) {
store.filter("Month", 9);
}, 300);
}
}]*/,
items: [{
xtype: 'LocationStatisticsPerMonthChart',
itemId: 'LocationStatisticsPerMonthChart',
anchor: '2000, -10',
//height: 400,
// width: 2000,
}]
}],
dockedItems: [{
xtype: 'TitleToolbar',
dock: 'top',
title: Resources.t('RegistrationsPerUnit'),
items: ['->', {
iconCls: 'iconRefresh',
itemId: 'refresh',
scope: this,
handler: function (btn) {
var store = btn.up('panel').down('LocationStatisticsPerMonthChart').getStore();
//store.removeAll();
store.load();
}
}]
}]
}]
});
The best way is to use a function, I'll give you an example:
We have a store, let's call it StoreA, and another store StoreB
var storeA = something.getStore();
var storeB = somethingElse.getStore();
storeA.filterBy(function(record) {
return storeB.find("name", record.data.name) != -1;
});
So basicly in this example, if the name is in storeB (find returns an index), it will filter it out from storeA's contents.
Unfortunately, you will have to re-do the exact same filter every time a new record is added or updated... so what I do is bind a function that does this to the load, update, delete, etc.. events.
You only need to filter the related data store. To accomplish this use the filter method as follows:
chart.store.filter("Month", 10);
You can always remove the filtering on the store by calling clearFilter store's method,
chart.store.clearFilter();
Take into account that you need to remove previous filters when applying new ones otherwise the each new applied filter will stack with the current ones
You can see a small example based on your code here. Hope it helps you to solve your problem.

ext js multiple instances of same grid

I'm having an issue with multiple instances of an ext js grid all showing the same data. I am using Ext js 4.1.1.
I have a main tab panel. In that panel, there are multiple people tabs. Inside each person tab is a details tab and a family tab.
The details tab is a simple form with text boxes, combo boxes, etc. The family tab has both a dataview and a grid.
If only one person tab is open at a time, everything works fine. As soon as a second person is opened, the family tabs look the same (both the dataview and the grid). It seems to me that the problem has something to do with the model. Perhaps they are sharing the same instance of the model, and that is causing one refresh to change all the data. The dataview and the grid both have the same problem, but I think that if I can fix the problem with the grid, then I can apply the same logic to fix the dataview. I will leave the code for the dataview out of this question unless it becomes relevant.
PersonTab.js
Ext.require('Client.view.MainTab.PersonDetailsForm');
Ext.require('Client.view.MainTab.PersonFamilyForm');
Ext.require('Client.view.MainTab.EventForm');
Ext.define('Client.view.MainTab.PersonTab',
{
extend: 'Ext.tab.Panel',
waitMsgTarget: true,
alias: 'widget.MainTabPersonTab',
layout: 'fit',
activeTab: 0,
tabPosition: 'bottom',
items:
[
{
title: 'Details',
closable: false,
xtype: 'MainTabPersonDetailsForm'
},
{
title: 'Family',
closable: false,
xtype: 'MainTabPersonFamilyForm'
},
{
title: 'page 3',
closable: false,
xtype: 'MainTabEventForm'
}
]
});
MainTabPersonFamilyForm.js
Ext.require('Client.view.MainTab.PersonFamilyHeadOfHouseholdDataView');
Ext.require('Client.view.MainTab.PersonFamilyGrid');
Ext.define('Client.view.MainTab.PersonFamilyForm',
{
extend: 'Ext.form.Panel',
alias: 'widget.MainTabPersonFamilyForm',
waitMsgTarget: true,
padding: '5 0 0 0',
autoScroll: true,
items:
[
{
xtype: 'displayfield',
name: 'HeadOfHouseholdLabel',
value: 'The head of my household is:'
},
{
xtype: 'MainTabPersonFamilyHeadOfHouseholdDataView'
},
{
xtype: 'checkboxfield',
boxLabel: "Use my Head of Household's address as my address",
boxLabelAlign: 'after',
inputValue: true,
name: 'UseHeadOfHouseholdAddress',
allowBlank: true,
padding: '0 20 5 0'
},
{
xtype: 'MainTabPersonFamilyGrid'
}
],
config:
{
idPerson: ''
}
});
MainTabPersonFamilyGrid.js
Ext.require('Client.store.PersonFamilyGrid');
Ext.require('Ext.ux.CheckColumn');
Ext.define('Client.view.MainTab.PersonFamilyGrid',
{
extend: 'Ext.grid.Panel',
alias: 'widget.MainTabPersonFamilyGrid',
waitMsgTarget: true,
padding: '5 0 0 0',
xtype: 'grid',
title: 'My Family Members',
store: Ext.create('Client.store.PersonFamilyGrid'),
plugins: Ext.create('Ext.grid.plugin.CellEditing'),
viewConfig:
{
plugins:
{
ptype: 'gridviewdragdrop',
dragGroup: 'PersonFamilyGridTrash'
}
},
columns:
[
{ text: 'Name', dataIndex: 'Name'},
{ text: 'Relationship', dataIndex: 'Relationship', editor: { xtype: 'combobox', allowblank: true, displayField: 'display', valueField: 'value', editable: false, store: Ext.create('Client.store.Gender') }},
{ xtype: 'checkcolumn', text: 'Is My Guardian', dataIndex: 'IsMyGuardian', editor: { xtype: 'checkboxfield', allowBlank: true, inputValue: true }},
{ xtype: 'checkcolumn', text: 'I Am Guardian', dataIndex: 'IAmGuardian', editor: { xtype: 'checkboxfield', allowBlank: true, inputValue: true } }
],
height: 200,
width: 400,
buttons:
[
{
xtype: 'button',
cls: 'trash-btn',
iconCls: 'trash-icon-large',
width: 64,
height: 64,
action: 'trash'
}
]
});
PersonFamilyGrid.js (store)
Ext.require('Client.model.PersonFamilyGrid');
Ext.define('Client.store.PersonFamilyGrid',
{
extend: 'Ext.data.Store',
autoLoad: false,
model: 'Client.model.PersonFamilyGrid',
proxy:
{
type: 'ajax',
url: '/Person/GetFamily',
reader:
{
type: 'json'
}
}
});
PersonFamilyGrid.js (model)
Ext.define('Client.model.PersonFamilyGrid',
{
extend: 'Ext.data.Model',
fields:
[
'idFamily',
'idPerson',
'idFamilyMember',
'Name',
'Relationship',
'IsMyGuardian',
'IAmGuardian'
]
});
relevant code from the controller:
....
....
var personTab = thisController.getMainTabPanel().add({
xtype: 'MainTabPersonTab',
title: dropData.data['Title'],
closable: true,
layout: 'fit',
tabpanelid: dropData.data['ID'],
tabpaneltype: dropData.data['Type']
});
personTab.items.items[0].idPerson = dropData.data['ID'];
personTab.items.items[1].idPerson = dropData.data['ID'];
thisController.getMainTabPanel().setActiveTab(personTab);
....
....
You're setting the store as a property on your grid prototype and creating it once at class definition time. That means that all your grids instantiated from that class will share the exact same store.
Note that you're also creating a single cellediting plugin that will be shared with all instantiations of that grid as well. That definitely won't work. You likely will only be able to edit in either the first or last grid that was instantiated.
In general you should not be setting properties like store, plugins, viewConfig or columns on the class prototype. Instead you should override initComponent and set them inside that method so that each instantiation of your grid gets a unique copy of those properties.
Ext.define('Client.view.MainTab.PersonFamilyGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.MainTabPersonFamilyGrid',
waitMsgTarget: true,
padding: '5 0 0 0',
title: 'My Family Members',
height: 200,
width: 400
initComponent: function() {
Ext.apply(this, {
// Each grid will create its own store now when it is initialized.
store: Ext.create('Client.store.PersonFamilyGrid'),
// you may need to add the plugin in the config for this
// grid
plugins: Ext.create('Ext.grid.plugin.CellEditing'),
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragGroup: 'PersonFamilyGridTrash'
}
},
columns: /* ... */
});
this.callParent(arguments);
}
});
It's hard to tell exactly, but from the code you have submitted it appears that you are not setting the id parameter on your tabs and your stores, which causes DOM collisions as the id is used to make a component globally unique. This has caused me grief in the past when sub-classing components (such as tabs and stores) and using multiple instances of those classes.
Try giving each one a unique identifier (such as the person id) and then referencing them using that id:
var personTab = thisController.getMainTabPanel().add({
id: 'cmp-person-id',
xtype: 'MainTabPersonTab',
...
store: Ext.create('Client.store.PersonFamilyGrid',
{
id: 'store-person-id',
...
});
Ext.getCmp('cmp-person-id');
Ext.StoreManager.lookup('store-person-id');
Hope that helps.

Sencha ExtJs Grid refresh after saving store

I have an ExtJS grid with a toolbar button to save the date. The save works and the data is stored. But the grid is not refreshed. How do I reload the grid data after the save?
Ext.define('MyLodge.view.content.MemberGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.membergrid',
initComponent: function(){
var rowEditing = Ext.create('Ext.grid.plugin.RowEditing');
var store = Ext.create('MyLodge.store.Members');
Ext.apply(this, {
height: this.height,
plugins: [rowEditing],
store: store,
stripeRows: true,
columnLines: true,
columns: [{
id :'id',
text: 'ID',
width: 40,
sortable: true,
dataIndex: 'id'
},{
text : 'Name',
flex: 1,
sortable : true,
dataIndex: 'name',
field: {
xtype: 'textfield'
}
},{
text : 'E-Mail',
width : 150,
sortable : true,
dataIndex: 'email',
field: {
xtype: 'textfield'
}
},{
text : 'Href',
width : 200,
sortable : true,
dataIndex: 'href',
field: {
xtype: 'textfield'
}
}],
dockedItems: [{
xtype: 'toolbar',
items: [{
text: 'Add',
iconCls: 'icon-add',
handler: function(){
// empty record
store.insert(0, new MyLodge.model.Member());
rowEditing.startEdit(0, 0);
}
}, {
text: 'Delete',
iconCls: 'icon-delete',
handler: function(){
var selection = grid.getView().getSelectionModel().getSelection()[0];
if (selection) {
store.remove(selection);
}
}
},'-',{
text: 'Save',
iconCls: 'icon-save',
handler: function(){
store.sync();
}
}]
}]
});
this.callParent(arguments);
}
});
You can load store in callback of sync
store.sync({
success: function( response ) {
store.load();
}
});
You will probably want to call store.reload() in a callback from store.save() (what is store.save() anyway? it is not part of Ext.data.Store interface)

container control as a grid editor does not update values

So I have a grid with two columns, the first has just text, the second needs to have a custom control (with a checkbox and a combo box)
Check the screenie:
Here is a link to a screenie:
The Problem:
When I click update to update the row. The first column gets updated, but the second column doesn't
I naively added a getValue() into my custom control but no luck!! (Note: I'm using row editing plugin)
Here is my code:
Ext.define('MainGrid', {
extend: 'Ext.grid.Panel',
//defs for all the toolbars and buttons
plugins: [rowEditing],
columns: [
{
xtype: 'rownumberer'
},
{
xtype: 'gridcolumn',
text: 'Column Titles',
dataIndex: 'ColumnTitle',
editor: {
xtype: 'textfield',
}
},
{
xtype: 'gridcolumn',
sortable: false,
align: 'center',
dataIndex: 'IssueCondition',
editor: {
xtype: 'reportpopulation'
}]
});
The reportpopulation is the custom control here. Here is the code for it:
Ext.define('SelectPopulation', {
extend: 'Ext.container.Container',
itemId: 'ctrSelectpopulation',
alias: 'widget.reportpopulation',
layout: {
type: 'hbox'
},
initComponent: function () {
//code to add combo box and checkbox snipped
....
},
getValue: function () {
//This doesn't work!
return "Booo";
}
});
So clicking Update doesn't :
Is there something I'm missing?
Should I inherit from FieldBase? Can I use multiple controls and create something like the screenie with FieldBase?
This works, even your getValue() was working, the problem is that you used a custom type value on that grid column (IssueCondition) and did not specified any renderer for it, try something like this:
Ext.define('MainGrid', {
extend: 'Ext.grid.Panel',
height: 300,
plugins: [Ext.create('Ext.grid.plugin.RowEditing', {
clicksToEdit: 1
})],
columns: [{
xtype: 'rownumberer'
}, {
xtype: 'gridcolumn',
text: 'Column Titles',
dataIndex: 'ColumnTitle',
editor: {
xtype: 'textfield'
}
}, {
xtype: 'gridcolumn',
sortable: false,
text: "Issue Condition",
align: 'center',
dataIndex: 'IssueCondition',
width: 200,
editor: {
xtype: 'reportpopulation'
},
renderer: function (v, attr, rec) {
console.info(arguments);
return 'cb: ' + rec.data.IssueCondition.cb + ' combo: ' + rec.data.IssueCondition.combo;
}
}],
store: Ext.create("Ext.data.Store", {
fields: ["ColumnTitle", "IssueCondition"],
proxy: {
type: "memory",
reader: {
type: "json"
}
}
})
});
Ext.define('SelectPopulation', {
extend: 'Ext.container.Container',
itemId: 'ctrSelectpopulation',
alias: 'widget.reportpopulation',
layout: {
type: 'hbox'
},
initComponent: function () {
Ext.apply(this, {
items: [{
xtype: "checkbox"
}, {
xtype: "combobox",
allowBlank: false,
store: [
[0, 'Zero'],
[1, 'One'],
[2, 'Two']
]
}]
});
this.callParent(arguments);
},
getValue: function () {
return {
cb: this.child('checkbox').getValue(),
combo: this.child('combobox').getValue()
};
}
});
Be aware that this is just an example.
Check the Fiddle here
Hope this helps.

infinite scroll not rendering

I'm trying to use ExtJS4.1 infinite scroll feature.
The ajax calls are being made, the data returned, but only the first page loads.
What am I doing wrong? When I scroll down nothing happens.
My code:
Store:
Ext.define('BM.store.Tests', {
extend: 'Ext.data.Store',
model: 'BM.model.Test',
storeId: 'Tests',
buffered: true,
leadingBufferZone: 50,
pageSize: 25,
purgePageCount: 0,
autoLoad: true
});
The proxy is in the model:
proxy: {
type: 'ajax',
api: {
create: '../webapp/tests/create',
read: '../webapp/tests',
update: '../webapp/tests/update'
},
reader: {
type: 'json',
root: 'tests',
successProperty: 'success'
}
}
The grid:
Ext.define('BM.view.test.MacroList', {
extend: 'Ext.grid.Panel',
alias:'widget.macro-test-list',
store: 'Tests',
// loadMask: true,
// selModel: {
// pruneRemoved: false
// },
// viewConfig: {
// trackOver: false
// },
verticalScroller: {
numFromEdge: 5,
trailingBufferZone: 10,
leadingBufferZone: 20
},
initComponent: function() {
this.columns = [
{
xtype: 'gridcolumn',
dataIndex: 'name',
text: 'Name'
},
{
xtype: 'datecolumn',
dataIndex: 'created',
text: 'Date Created',
format: 'd-M-Y'
},
{
xtype: 'datecolumn',
dataIndex: 'changed',
text: 'Last Updated',
format: 'd-M-Y'
}
];
this.callParent(arguments);
}
The only thing that's different between my implementation and the one in the examples, is that my grid is not rendered to the body.
The viewport contains a border layout.
The grid is part of the west region panel:
{
collapsible: true,
region: 'west',
xtype: 'macro',
width: 500
}
The macro panel:
Ext.define('BM.view.Macro', {
extend: 'Ext.panel.Panel',
alias: 'widget.macro',
title: 'Tests',
layout: {
type: 'vbox',
align: 'stretch'
},
items: [
{
id: "macro-test-list-id",
xtype: 'macro-test-list',
flex: 1
},
{
id: "macro-report-panel-id",
xtype: 'macro-report-list',
title: false,
flex: 1
},
{
id: "macro-report-list-id-all",
xtype: 'macro-report-list-all',
flex: 1,
hidden: true,
layout: 'anchor'
}
]
});
I've tried many many things, changing layouts, giving the grid a fixed height, etc...
Nothing works, scroll down, and the grid doesn't refresh.
One other piece of information: The DB contains 53 records of data. I'm getting the 3 ajax calls, but only the first 25 records appear (as I requested).
Any thoughts?
It sounds like you might be forgetting to put the total property in the server's JSON response. Does your answer have a structure like this:
{
"total": 53,
"tests": [(...)]
}
The totalProperty name is defined in the Reader configuration and defaults to total.
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.reader.Reader-cfg-totalProperty
You need to upgrade to ExtJS 4.2!

Resources