I'm creating widget for IBM BusinessSpace, and I'm having some difficulties with paging.
Data are succesfully returned from database (using restlet) and displayed in a grid. Navigation is also displayed below the grid (next page, previous page, go to page, number of pages, etc).
If I, for example, have 3 pages, 5 rows per page, and want to navigate to second page, when I click on the page number 2, data reloads (it seems like restlet is called again), and first 5 rows (displayed on the first page) are showed on this one too. If I choose any other navigation option (next page, ...), same thing happeneds. Bottom line, every click results in first 5 rows from my database.
Any clue on how to resolve this issue?
Here's a code regarding this:
dojo.require("dojo.data.ObjectStore");
dojo.require("dojox.grid.enhanced.plugins.Pagination");
dojo.require("dojox.grid.EnhancedGrid");
dojo.require("dojo.store.JsonRest");
var restStore = new dojo.store.JsonRest({target:"https://localhost:9443/Application/hello"});
var dataStore = dojo.data.ObjectStore({objectStore: restStore});
dojo.ready(function(){
var grid = new dojox.grid.EnhancedGrid({
store: dataStore, <br>
structure: [
{name:"Value", field:"value", width: "auto"},
{name:"RequestID", field:"requestId", width: "auto"},
{name:"ID", field:"id", width: "auto"},
{name:"Name", field:"name", width: "auto"}
],
columnReordering: true,
clientSort: true,
rowSelector: '20px',
rowsPerPage: 5,
autoHeight: true,
plugins: {
pagination: {
pageSizes: ["5", "10", "15", "All"], // page length menu options
description: true, // display the current position
sizeSwitch: true, // display the page length menu
pageStepper: true, // display the page navigation choices
gotoButton: true, // go to page button
position: "bottom" // position of the pagination bar
}
}
}, "gridDiv");
grid.startup();
});
When using jsonRest in a grid, when you scroll the records not shown are not loaded yet, at this moment jsonRest makes a request for the data needed to show, for this pager to work as expected, in your rest implementation you have to consume a header that dojo creates (Range: 0-24), this one is sent by dojo so you know the offset and limit for the data needed, for the response, you have to return a header (Content-Range: items 0-24/66), the numbers tell dojo from where to where it should be showing and how much total record are.
This is an example in php (assuming that db and response are actual objects):
$range = $request->headers->get('Range');
preg_match_all ('/.*?(\d+).*?(\d+)/is', $range, $matches);
$limit = $matches[2][0];
$offset = $matches[1][0];
$sql = "SELECT SQL_CALC_FOUND_ROWS * FROM table LIMIT {$limit} OFFSET {$offset}";
$result = $db->execute($sql);
$sql2 = "SELECT FOUND_ROWS()";
$count = $db->execute($sql2);
$response->setContent($result);
$response->headers->set('Content-Range', "items $offset-$limit/{$count}");
In jsonRest documentation there is some information.
Related
I am working on dojo enhanced grid view. I am able to display the grid in UI. But AnyColumn option is added as new column.
Example:
Any help will be appreciated...
Here is the Code
var mygrid = new EnhancedGrid({
id: "grid",
store: gridStore, //Data store passed as input
structure: gridStructure, //Column structure passed as input
autoHeight: true,
autoWidth: true,
initialWidth: width,
canSort : true,
plugins: {
filter: {
//Filter operation
isServerSide: true,
disabledConditions : {"anycolumn" : ["equal","less","lessEqual","larger","largerEqual","contains","startsWith","endsWith","equalTo","notContains","notEqualTo","notStartsWith","notEndsWith"]},
setupFilterQuery: function(commands, request){
if(commands.filter && commands.enable){
//filter operation
}
}
}
}, dojo.byId("mydatagrid"));
mygrid.startup();
Thanks,
Lishanth
First, do not use EnhancedGrid, instead use either dgrid or gridx.
I think by default anycolumn is added to the dropdown. If you want to remove then, I would suggest to
Register for click event on the filter definition
Iterate through the drop-down and remove the first entry which is anyColumn
or you can also try something like
dojo.forEach(this.yourgrid.pluginMgr.getPlugin('filter').filterDefDialog._cboxes, function(dropdownbox) {
dropdownbox._colSelect.removeOption(dropdownbox.options[0]);
});
Updated answer is. I know this is not the elegant way of doing it but it works.
//reason why I'm showing the dialog is that _cboxes of the filter are empty initially.
dijit.byId('grid').plugin('filter').filterDefDialog.showDialog();
dojo.forEach(dijit.byId('grid').pluginMgr.getPlugin('filter').filterDefDialog._cboxes, function(dropdownbox) {
var theSelect = dropdownbox._colSelect;
theSelect.removeOption(theSelect.options[0]);
});
//Closing the dialog after removing Any Column
dijit.byId('grid').plugin('filter').filterDefDialog.closeDialog();
I am using dgrid as follows:
query_grid: function(json_query, target, select){
var self = this;
require(["dojo/_base/declare",
"dgrid/Grid",
"dgrid/extensions/ColumnResizer",
"dgrid/Selection",
"dgrid/selector",
"dgrid/extensions/DijitRegistry",
"dgrid/extensions/Pagination"],
function(declare, Grid, ColumnResizer, Selection, selector, DijitRegistry, Pagination){
util.destroy("grid_"+json_query.path);
var columns = {};
if (select){
columns.widget = selector({
id: "widget",
label: " ",
selectorType: "radio",
resizeable: false,
width: 30});
}
var data = json_query.data;
for (var i=0; i<data.keys.length; i++){
columns[data.keys[i]] = {label: util.slice_path(data.keys[i], 2)};
}
var grid = new (declare([Grid, ColumnResizer, Selection, DijitRegistry, Pagination]))({
id: "grid_"+json_query.path,
columns: columns,
store: new Memory({data: data.records}),
selectionMode: select?"single":"none",
pagingLinks: 1,
pagingTextBox: true,
firstLastArrows: true
});
dojo.place(grid.domNode, target, 'last');
grid.refresh();
}
);
return json_query.path;
}
but when i look at the result, it always shows one record less then is present, until i click on a column header (resulting in a sort), and then all records are shown. Can anyone expain or help with a solution/workaround?
Replace grid.refresh() with grid.startup().
dgrid will automatically call startup in cases where an instance is in document flow as soon as it's created. That's not the case here since you're placing it afterwards, so you need to call startup after it's in flow to tell it that it can perform geometry-sensitive operations.
Without calling startup, resize is never initially called. As a result, the grid doesn't properly account for the height of the header/footer, and one of your 10 rows is getting obfuscated. It gets fixed when you sort because dgrid/Grid's _setSort method calls resize in case the size of the header row changes due to the placement of the sort arrow.
The reason you can replace refresh with startup in this case is because startup calls refresh anyway.
So I'm a first time user of dgrid, and I'm currently building my tree grid like this:
var SelectionGrid = new declare([OnDemandGrid, Selection, Keyboard]);
var myGrid = new SelectionGrid({
store: myStore,
selectionMode: "single",
style: {
width: '99%',
height: '99%'
},
columns: columns
});
My problem is, the grid shows metadata for features I'm drawing in openlayers. I've written code in openlayers so that whenever I click on a feature on the map, it fires an event to scroll to that item in the grid and select it. The grid, however, doesn't pre-load the children for each parent, it only fetches the children when the parent row is expanded.
Currently I'm programmatically expanding every row and then reclosing them to force it to fetch, but it's terribly slow and ends up causing browser warnings about javascript taking too long to run, etc.
Is this a side effect of using OnDemandGrid? Is there anyway to just have all the data loaded so it's all available when the grid is rendered?
I had another issue and wanted to post another answer in case anybody has the same problem. When not using the Tree plugin and just using the OnDemandGrid, I couldn't programattically scroll to items in the grid that hadn't been loaded because the element for the row was null.
I found a property that tells the OnDemandGrid the minimum number of items to load from the store, and just set it to the length of my data, so it loads everything at once. I know that defeats the purpose/benefit of the OnDemandGrid, but it's the functionality I need. Here's the code:
var SelectionGrid = new declare([OnDemandGrid, Selection, Keyboard, DijitRegistry]);
var grid = new SelectionGrid({
store: store,
selectionMode: "single",
columns: columns,
minRowsPerPage: data.length,
farOffRemoval: 100000
});
Here's the reference for minRowsPerPage and farOffRemoval:
http://dojofoundation.org/packages/dgrid/tutorials/grids_and_stores/
I wasn't able to preload all my data, but I just discovered the glory of dojo/aspect. Now I find the parent item that needs expanded and I just build some code inside an aspect/after block that gets executed as soon as that row is finished expanding/loading:
aspect.after(grid, "expand", function (target, expand) {
var row = grid.row(id);
console.info("found row: ", row)
grid.bodyNode.scrollTop = row.element.offsetTop;
grid.clearSelection();
grid.select(row);
},
true);
grid.expand(item.id, true);
In my dojo dataGrid if i select 7th and 8th rows for example in the first page and if i move to second page by using pagination feature. The rows(7th and 8th row which are selected in first page) are selected by default in the second page also.
Here is my grid:
var grid = new dojox.grid.EnhancedGrid({
id: 'linesGrid',
style: 'width:950px;height:250px;',
store: store,
structure: layout,
rowSelector: '20px',
plugins: {
indirectSelection: {headerSelector:true, width:"40px", styles:"text-align: center;"},
pagination: {
pageSizes: ["25", "50", "100", "All"],
description: true,
sizeSwitch: true,
pageStepper: true,
gotoButton: true,
/*page step to be displayed*/
maxPageStep: 4,
/*position of the pagination bar*/
position: "bottom"
}
}
}, document.createElement('div'));
Set the grid to keepSelection : true. This will maintain the proper rows selected.
You need to do a yourGrid.selection.deselectAll(); before showing the next page.
EDIT:
Part of this question was also discussed here:
not able to call a function on pagination dojo enhancedGrid
I am creating the dojo Grid as below and I am using the indirectSelection plugin for creating a checkbox, as below, but by default the checkboxes will come at the first column of the grid. How do I make it to come at the last column?
var grid = new dojox.grid.EnhancedGrid({
id: 'serialsGrid',
style: 'width:auto;height:250px;',
store: store,
structure: layout,
rowSelector: '20px',
plugins: {
indirectSelection: {name:'Requested',headerSelector:true, width:"40px", styles:"text-align: center;"},
pagination: {
pageSizes: ["25", "50", "100", "All"],
description: true,
sizeSwitch: true,
pageStepper: true,
gotoButton: true,
/*page step to be displayed*/
maxPageStep: 4,
/*position of the pagination bar*/
position: "bottom"
}
}
}, document.createElement('div'));
/*append the new grid to the div*/
//var temp=grid.domNode;
dojo.byId("serialsGridDiv").appendChild(grid.domNode);
/*Call startup() to render the grid*/
serialsGridCopy=grid;
grid.startup();
});
The plugin itself has no capabilities of doing so as far as I know so I started looking at the functions the EnhancedGrid itself has and stumbled upon the function moveColumn() in grid.layout.
The documentation itself (here) was not really usefull, but I used it to move every column one position ahead so that the first column would become the last one.
I also made a working JSFiddle to demonstrate which you can see here. The code that is moving the columns can be found at the bottom of the code:
for (var i = 1;i < grid.layout.cells.length;i++) {
grid.layout.moveColumn(1, 1, i, i-1, grid.layout);
}
What it does is the following: it moves every column starting from index 1, so that means all columns except the indirectSelection column one step ahead (i-1).