I have a extjs 4 grid panel with remote stores.
On the renderer of column there is function, which change ID to NAME.
Mostly times it works fine, but sometimes (~40%) the grid shows with empty columns.
I've tried to debug - the store is defined, but its items are empty.
To my mind store not loaded yet, or already destroyed (if it is possible).
How to correctly show grid, with full data?
There is my simplified code:
Loading needed components
Ext.Loader.setConfig({
enabled:true
});
Ext.Loader.setPath('Ext.ux', '/js/ux');
Ext.require([
'Ext.grid.*',
'Ext.data.*'
]);
Ext.onReady(function () {
Create models
Ext.define('Expense', {
extend:'Ext.data.Model',
fields:[
{name:'id', type:'number'},
{name:'cost_id', type:'string'},
{name:'comment', type:'string'}
]
});
Ext.define('Cost', {
extend:'Ext.data.Model',
fields:[
{name:'id', type:'string'},
{name:'name', type:'string'},
{name:'displayname', type:'string'}
]
});
Create stores
store = Ext.create('Ext.data.Store', {
autoDestroy:true,
model:'Expense',
autoLoad:true,
autoSync:true,
pageSize:30,
proxy:{
type:'ajax',
url:'/expenses/gettable',
reader:{
type:'json',
root:'data',
record:'Expense'
}, writer:{
type:'json'
},
api:{
create:'/expenses/create',
update:'/expenses/update',
destroy:'/expenses/delete'
}
}
});
costsStore = Ext.create('Ext.data.Store', {
autoDestroy:true,
model:'Cost',
autoLoad:true,
autoSync:true,
proxy:{
type:'ajax',
url:'/costs/gettable',
reader:{
type:'json',
record:'Cost'
}, writer:{
type:'json',
allowSingle:false
},
api:{
create:'/costs/create',
update:'/costs/update'
}
}
});
Configure grid panel
grid = Ext.create('Ext.grid.Panel', {
store:store,
autoSync:true,
columns:[
{
id:'comment',
header:'Задача',
dataIndex:'comment',
flex:5
},
{
id:'cost',
header:'Cost',
dataIndex:'cost_id',
flex:5,
editor:{
xtype:'combobox',
store:costsStore,
valueField:'id',
displayField:'name',
name:'cost_id'
},
renderer:function (value, meta, record) {
if (value != '') {
ind = costsStore.find('id', value);
elem = costsStore.getAt(ind);
if (elem) {
return elem.data['name'];
}
}
}
}
],
renderTo:'editor-grid'
});
});
I've tried to manually load stores on grid render event:
grid = Ext.create('Ext.grid.Panel', {
listeners:{
beforerender:function(){
store.load();
costsStore.load();
}
}
...
});
It is decrease empty table to ~10% cases, but not 0%...
The only way I've found is to set delay after loading all stores, and then show grid, something like this:
listeners:{
'load':function(){
window.setTimeout("getGrid()", 1000);
}
}
Where getGrid() is the function with creating grid.panel.
What I have to do, to show grid only after all stores loaded, or show error if data can't load?
As sra suggested - your problem seems to stem from using a store within a renderer, while you cannot be sure that store is loaded.
I have described what I think is the most elegant solution to this problem in this answer, with some code examples.
Related
I'm new to extjs and I'm having some trouble loading json data to a grid. In the debugger I can see the grid's store and columns are being populated accurately the way I want. But the data is not displaying in the grid. I'm not sure why. But my grid is not loading the data.
What am I doing wrong?
Thank you in advance.
the grid view:
Ext.define('searchadmin.view.reports.DynamicGrid' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.dynamicGrid',
title : 'Results',
columns: [],
columnLines : true,
sortableColumns : false,
autoScroll : true,
viewConfig : {
stripeRows : false,
loadMask:true
}
});
The store:
Ext.define('searchadmin.store.DynamicGridStore', {
extend : 'Ext.data.Store',
model: 'searchadmin.model.DynamicGridModel',
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'data'
}
}
});
The model:
Ext.define('searchadmin.model.DynamicGridModel', {
extend: 'Ext.data.Model',
fields: []
});
The view config for the page on which the above grid is in this gist:
Reports.js
The Reports controller that contains the code to dynamically compose the model and store is in the handleSelectQueryResult() in: ReportsController
You will have to use reconfigure method of grid instead of just assigning columns and store like this in handleSelectQueryResult function of ReportsController.js.
grid.columns = _columns; //will not work
grid.store = queryStore; //will not work
Also note that ComponentQuery.query returns an array.
Try this way.
var grid = Ext.ComponentQuery.query('#dynamicGridId')[0]; //or var grid = Ext.getCmp('dynamicGridId');
grid.reconfigure(queryStore, _columns);
The view looks like so:
Ext.define('GridGeneral.view.GridGeneralPanel',{
extend:'Ext.grid.Panel',
alias:'widget.GridGeneralPanel',
initComponent:function(){
var me = this;
Ext.applyIf(me,{
layout:'fit',
border:false,
columnLines:true,
loadMask:true,
viewConfig:{},
columns:[]
});
me.callParent(arguments);
}
});
The store is following:
Ext.define('GridGeneral.store.GridGeneralStore',{
extend:'Ext.data.BufferedStore',
model:'GridGeneral.model.GridGeneralModel',
constructor:function(cfg){
var me = this;
cfg = cfg || {};
me.callParent([
Ext.apply({
autoLoad:true,
leadingBufferZone:300,
pageSize:100,
proxy:{
type:'ajax',
url:'/modules/grid/data/',
extraParams:{
format:'json'
},
reader:{
rootProperty:'data',
totalProperty:'total'
}
}
},cfg)
])
}
});
This is the controller:
Ext.define('GridGeneral.controller.GridGeneralController',{
extend:'Ext.app.Controller',
models:['GridGeneralModel'],
stores:['GridGeneralStore'],
views:['GridGeneralPanel'],
refs:[{
ref:'gridPanel',
selector:'GridGeneralPanel'
}],
init:function(){
Ext.getStore('GridGeneralStore').addListener('metachange',
this.metaChanged, this);
},
metaChanged:function(store, meta){
this.getGridPanel().reconfigure(store, meta.columns);
}
});
And, finally, this is what the server returns to the client:
{"msg":"","total":"160","data":[{"stream_name":[...],"stream_size":[0],"_version_":"123456",
"id":"abcd-efgh-hijk-lmno"},.....],"metaData":{...}]}
Almost everything seems ok - grid is rendered, columns are rendered and so on. But the only problem I see is that store not loaded to the view - I see no grid rows at all. So, what am I doing wrong?
EDIT
So, nobody in the world can create mvc with dynamic infinite grid?
EDIT
It is obviously some bug. I moved to extjs 6.0 and now everything works fine.
I am using dgrid and i am attempting to set the dataStore externally. When the page loads i call aliasTicket.load() to create the grid. At the time the grid is loading the datasource is null. When a query is executed the setAliasSource(aliasData); is set.
There are no errors however the grid is still empty. The aliasStore is being updated with data however it isn't being reflected on the grid even after the grid is refreshed. How can i get the data reflected in the grid after the query?
Javascript Object
var aliasTicket = (function (){
var aliasData = [];
require([ "dojo/store/Observable", "dojo/store/Memory"]);
var aliasStore = new dojo.store.Observable(new dojo.store.Memory({
data: aliasData,
idProperty: "id"
}));
return{
load:function(){
require([
........
], function(declare, Memory, OnDemandGrid, ColumnSet, Selection,
selector, Keyboard, DijitRegistry, editor, ColumnHider,
registry, Observable,lang) {
aliasData = this.aliasData;
var Store = this.aliasStore = new dojo.store.Observable(new dojo.store.Memory({
data: aliasData,
idProperty: "id"
}));
console.log(Store);
var CustomAliasNameGrid = declare([OnDemandGrid, selector, Selection, Keyboard, editor, DijitRegistry, ColumnHider]);
var aliasNameGrid = new CustomAliasNameGrid({
store: Store,
columns: {
id: {
label: "Id",
field: "id",
hidden: true,
autoSizeColumn: true
},
employeeTicketId: {
label: "Employee Ticket Id",
field: "employeeTicketId",
hidden: true,
autoSizeColumn: true
},
chkBox: selector({}),
aliasName: {
label: "Alias Names",
field: "aliasTicketName",
autoSizeColumn: true,
formatter: function(str) {
return str.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
}
}
},
selectionMode: "none",
loadingMessage: "Loading data...",
noDataMessage: "No results found....",
allowSelectAll: true
}, "aliasNameGrid");
aliasNameGrid.refresh()
});
},
setAliasSource: function (data){
console.log(data);
this.aliasSource = data;
},
setAliasData: function (data){
this.aliasData = data;
},
getAliasSource: function (){
return this.aliasSource;
}
};
})();
Setting Data Store Data
aliasData = [{.....},
{.....},
{......];
require(["dijit/dijit"]);
aliasTicket.setAliasSource(aliasData);
dijit.byId('aliasNameGrid').refresh();
You are setting 'this.Store' to an object array, not a real 'dojo store' object. Following your code I can not see where you actually use 'this.Store'. Inside the grid code I do see a local variable named 'Store'.
So I'm not sure if I'm following your code example here but, you should 'set' the store of the grid and then refresh it. Something like this.
setAliasSource: function (data){
console.log(data);
this.Store = data;
dijit.byId('aliasNameGrid').set("store",new dojo.store.Observable(new dojo.store.Memory({ data: data,idProperty: "id"}));
dijit.byId('aliasNameGrid').refresh();
},
Using the example from https://help.rallydev.com/apps/2.0rc2/doc/#!/guide/timebox_filtering for a timebox required app, how do I convert the cardBoard view into a grid?
This is the base code:
Ext.define('Rally.guide.ReleaseFilteredBoard', {
extend: 'Rally.app.TimeboxScopedApp',
scopeType: 'release',
onScopeChange: function(scope) {
if(!this.board) {
this.board = this.add({
xtype: 'rallycardboard',
storeConfig: {
filters: [scope.getQueryFilter()]
}
});
} else {
this.board.refresh({
storeConfig: {
filters: [scope.getQueryFilter()]
}
});
}
}
});
It seems that I can simply change the xtype to 'rallygrid' and based on docs it should work but it seems to need a model defined as well - how do I get the model details out of the timebox scope to feed into the grid?
You may wish to check out the example code for Rally.ui.grid.Grid.
Here's a quick sample of how one might apply the Timebox filter to a grid:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
grid: null,
launch: function() {
var filters = [];
var timeboxScope = this.getContext().getTimeboxScope();
if(timeboxScope) {
filters.push(timeboxScope.getQueryFilter());
}
this.getFilteredStoryModel(filters);
},
onTimeboxScopeChange: function(newTimeboxScope) {
var newFilters = [];
var updatedTimeboxScope = this.getContext().getTimeboxScope();
if (this.grid) {
this.grid.destroy();
}
if (updatedTimeboxScope) {
newFilters.push(newTimeboxScope.getQueryFilter());
}
this.getFilteredStoryModel(newFilters);
},
getFilteredStoryModel: function(queryFilters) {
Rally.data.ModelFactory.getModel({
type: 'UserStory',
success: function(model) {
this.grid = this.add({
xtype: 'rallygrid',
model: model,
columnCfgs: [
'FormattedID',
'Name',
'Owner',
'Iteration'
],
storeConfig: {
filters: queryFilters
}
});
},
scope: this
});
}
});
To show the timebox filter, choose the type of filter you desire when first setting up your Custom Page in Rally. The "onTimeboxScopeChange" callback responds to events triggered by the timebox selector setup and configured on the Custom Page container itself. No code is needed to setup the timebox selector, rather you do it via the Rally UI when creating a new Custom Page:
Select the type of filter (Release or Iteration):
(1) Note that the filter shows on the "My New Custom Page" Container. (2) Any app that you add to "My New Custom Page" will then have the timebox filter available/applied:
Add Custom HTML App:
Paste in Code and Save:
Iteration-filtered Grid:
Alternatively, if you don't want a timebox filter that applies to an entire Custom Page container, you can elect to use Rally.ui.combobox.ReleaseComboBox or Rally.ui.combobox.IterationComboBox
In your App code itself, and manage the filtering via callbacks from either of these components. This filtering would be totally "within-app" and wouldn't rely on the Custom Page-wide timebox component.
I can't find this anywhere and i don't know why the cross domain REST request is not solved by dojo. anyways here is the problem:
I am implementing dojo data-grid, and i am trying to get the data for the grid from a WCF that is not in my domain, so i crossdomain problem is raised and i am trying to over come this problem by using JSONP.
but i am a newbie in dojo so i am probably doing something wrong. here is my code:
require([
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dojox/grid/DataGrid",
"dojo/data/ObjectStore",
"dojo/query",
"dijit/form/Button",
"dojo/domReady!",
"dojo/request/script","dojo/dom-construct"
],function(script, domConstruct){
//make the request just as before
script.get("http://localhost:8060/ListService.svc/LoadLists?uid=c4446476-15e6-e111-9ecb-b7c5971d170a", {
jsonp: "callback",
query: {q: "#dojo"}
}).then(function(data){
test = data;
}).then(function(){
console.log(results);
});
}, function (JsonRest, Memory, Cache, DataGrid, ObjectStore ,query) {
grid = new DataGrid({
store: dataStore = test,
structure: [
{ name: "Blog Id", field: "id", width: "50px", },
{ name: "Name", field: "listtype", width: "200px",classes:"Name" },
{ name: "Phone Number", field: "longlevel", width: "200px",classes:"test" }
]
}, "gridTest"); // make sure you have a target HTML element with this id
grid.startup();
dojo.query("body").addClass("claro");
grid.canSort = function () { return false; };
});
the error i am getting is query is not a function. any ideas how to implement this correctly.
Simple mistake just put the data grid command inside the first then with the data returning
require([
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dojox/grid/DataGrid",
"dojo/data/ObjectStore",
"dojo/query",
"dijit/form/Button",
"dojo/domReady!",
"dojo/request/script","dojo/dom-construct"
],function(script, domConstruct){
//make the request just as before
script.get("http://localhost:8060/ListService.svc/LoadLists?uid=c4446476-15e6-e111-9ecb-b7c5971d170a", {
jsonp: "callback",
query: {q: "#dojo"}
}).then(function(data){
function (JsonRest, Memory, Cache, DataGrid, ObjectStore ,query) {
grid = new DataGrid({
store: dataStore = test,
structure: [
{ name: "Blog Id", field: "id", width: "50px", },
{ name: "Name", field: "listtype", width: "200px",classes:"Name" },
{ name: "Phone Number", field: "longlevel", width: "200px",classes:"test" }
]
}, "gridTest"); // make sure you have a target HTML element with this id
grid.startup();
dojo.query("body").addClass("claro");
grid.canSort = function () { return false; };
})
}).then(function(){
console.log(results);
});
};
If you still find a problem probably because the grid is created before the request is returning from the wcf.
if that happened please use the Deferred in dojo 1.8 which make you in control of you processes sequence.
so you will be able to call the request give it some time and then put the data in the grid to be viewed.