dgrid always showing one record less then present - dojo

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.

Related

AnyColumn option added as new column in Dojo enhanced grid view

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();

How to dynamically add elements to a Dojo ComboBox

I have a Dojo combobox declaratively created using a standard HTML select. There is an onChange event on a separate textbox that invokes a function to get data from a server via XHR and elements of the response data become new options for the drop down.
I've been trying examples across the internet but nothing so far has worked. This is the code I'm currently trying with no errors. In fact, when I look at the contents of the store after the put, the data is in there.
When I click on the drop down after the data has been set, I get the error "_AutoCompleterMixin.js.uncompressed.js:557 Uncaught TypeError: Cannot read property 'toString' of undefined":
var newOptions = new Array();
for (var i = 0; i < jsonData.length; i++) {
newOptions[i] = { value: jsonData[i].dataID,
label: jsonData[i].dataName,
selected: i == 0};
}
var select = registry.byId("combobox");
select.store.put(newOptions, { overwrite: true });
And also "select.store.data = newOptions;".
And also moving the code around so "select.store.add(option)" is within the loop.
Though the combobox store is being populated in all three cases, I continue get the same error. There are no null values in the data. There are no blank values in the data.
What am I missing? No example anywhere, within the DOJO docs or anywhere else has this problem, even working jsFiddle examples.
I simply cannot see what the difference is other than the fact I'm adding more than one or two hard-coded values.
It takes:
newOptions[i] = { id: jsonData[i].dataID,
name: jsonData[i].dataName,
selected: i == 0};
not
newOptions[i] = { value: jsonData[i].dataID,
label: jsonData[i].dataName,
selected: i == 0};

Cytoscape : multiple instances and no graph display

I want to display several instances of cytoscape in a single page, in a time sequence: first one set of nodes are displayed on the graph, the user must interact with it (create edges), then he moves to a second graph (#cy0 is :hidden and #cy1 is :visible).
For code optimisation sake I wish to use the same initialisation function to display different successive sets of nodes. My initialisation function works fine in the first instance, but the graph is not created (cy.initrender() == false) in the second session. A command is probably missing, I tested a couple, but I don't see what to do.
Here is my code:
//elements
$(function(){ // on dom ready
var elesJson = {
nodes: [
{ data: { id: 'S', faveShape: 'rectangle',} }
...
],
edges: [
{ data: { id: 'loan', source: 'B', target: 'U' } },
...
],
};
// instance index
var indexLevel=0;
// cy initialisation
$("#cy"+indexLevel).cytoscape({
style: cytoscape.stylesheet()...
elements: elesJson,
ready: function(){
window.cy = this;});
// jQuery command to move from one instance to the other.
$('#next').click(function(){
$("#cy"+indexLevel).css("visibility","hidden");
indexLevel++;
$("#cy"+indexLevel).css("visibility","visible");
cy.load(elesJson);
cy.ready();
console.log(cy.initrender());
});
I am able to generate my node.collection, it is not empty, but the canvas element is not created and/or displayed within the #cy div, and cy.initrender() returns "false".
Any solution to this?
As noted in the docs for init, you must call cy.resize() if you play around with the cy div's display or position: http://js.cytoscape.org/#core/initialisation
cy.resize() : http://js.cytoscape.org/#core/viewport-manipulation/cy.resize
Edit: You may want to use z-index instead to simplify things...

Preload all children for dojo dgrid

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);

Hiding a series by default in a spider plot

I have a spider plot in using the graphing library of Dojo defined like this:
require([
"dojox/charting/Chart",
"dojox/charting/themes/Claro",
"dojox/charting/plot2d/Spider",
"dojox/charting/action2d/Tooltip",
"dojox/charting/widget/SelectableLegend",
"dojox/charting/axis2d/Default"
], function (Chart, theme, Spider, Tooltip, Legend, Default) {
var chart = new Chart(element).setTheme(theme).addPlot("default", {
type: Spider,
radius: 200,
fontColor: "black",
labelOffset: "-20"
});
var colors = ["blue", "red", "green", "yellow", "purple", "orange", "teal",
"maroon", "olive", "lime", "aqua", "fuchsia"];
$.each(factors, function (index, factor) {
chart.addAxis(factor.name, {
type: Default,
min: factor.min,
max: factor.max
});
});
$.each(presets, function (pIndex, preset) {
var data = [];
$.each(factors, function (fIndex, factor) {
data[factor.name] = preset.values[fIndex];
});
chart.addSeries(preset.short, data, {
fill: colors[pIndex % colors.length]
});
});
new Tooltip(chart, "default");
chart.render();
new Legend({
chart: chart,
horizontal: false
}, $(element).next(".legend")[0]);
});
I add a series for every member of an array called presets and I use a selectable legend that lets the user turn them on or off as they want. However, what I can't seem to find in the docs is how to start a series in the unselected, not visible state? What I ideally want to do is cap the number of series visible when the page loads because in some cases I have up to 14 presets and it just looks a mess until the user deselects a bunch. So I'd like to have, say, every preset above the first 5 be hidden at the start.
Here's a crude fiddle I've knocked to demonstrate. What I want is to have some of the series unselected when the plot is first displayed.
Update: I tried adding this after adding my series:
var checkboxes = $(".dijitCheckBoxInput").each((index, elem) => {
if (index > 4) {
elem.click();
}
});
Which works, but seems very fragile. If they change the class assigned to checkboxes, it'll break. Also, it prohibits me using more than one set of dojo checkboxes because I don't have a good way to tell the difference. (Note, the IDs of the checkboxes added by the SelectableLegend are dijit_form_CheckBox_0, dijit_form_CheckBox_1, etc, which also gives no useful information as to what they are related to). I thought I might be able to use the legend placeholder div as a way to select the descendant checkboxes, but it appears that Dojo replaces the placeholder entirely with a table.
i looked into the dojo code and found the area in which the shapes are toggled on & off whitin the SelectableLegend.js :
var legendCheckBox = query(".dijitCheckBox", legend)[0];
hub.connect(legendCheckBox, "onclick", this, function(e){
this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
legend.vanished = !legend.vanished;
e.stopPropagation();
});
The toggling process is very complex and is based on many local attributes:
_toggle: function(shapes, index, isOff, dyn, seriesName, plotName){
arrayUtil.forEach(shapes, function(shape, i){
var startFill = dyn.fills[i],
endFill = this._getTransitionFill(plotName),
startStroke = dyn.strokes[i],
endStroke = this.transitionStroke;
if(startFill){
if(endFill && (typeof startFill == "string" || startFill instanceof Color)){
fx.animateFill({
shape: shape,
color: {
start: isOff ? endFill : startFill,
end: isOff ? startFill : endFill
}
}).play();
}else{
shape.setFill(isOff ? startFill : endFill);
}
}
if(startStroke && !this.outline){
shape.setStroke(isOff ? startStroke : endStroke);
}
}, this);
}
I tried also checking & unchecking the dijit/form/Checkbox in a legend manually, but that does not trigger the _toggle function in any case, even if you do a render() / fullrender() on the chart.
With that in mind it seems that there is no other possibilty to toggle the series on and off than by firing the onclick events manually.
To make your code less fragile, you could access the Checkbox widgets within the legend manually using:
query(".dijitCheckBox", legend); // Should deliver an array containing
the widgets.
and triggering the onclick event on them. Their keynumber in the array should correspond to the order the series where added...
Dojo is a fine piece of work, please dont stop working with it !
dojox/charting/Series has an attribute called dirty which according to the API docs is a "flag indicating whether or not this element needs to be rendered".
Alternately, if you are limiting the display of some series you can write a separate interface for adding them. For example, loop over the first 5. Then create a select box or list of check boxes with all entries and an onchange event that calls chart.addSeries.
Keeping a reference to each series you create will allow you to later call destroy() or destroyRecursive() on it if the user no longer wishes it displayed.
So while ideally you could toggle the display of these series, the worst case senerio is that you just add, destroy, and read based on some user input.
Using a templated widget will allow you to keep this interface and the chart tightly linked and support reuse.
BTW, consider using "dojo/_base/array" and "dojo/query" in place of the jquery
I think i've got it !
I found another way to access the checkboxes ! It's the same way dojo uses internally to connect the "toggle code" to the onclick event. First take a look at this from SelectableLegend.js (Lines 150 - 156):
// toggle action
var legendCheckBox = query(".dijitCheckBox", legend)[0];
hub.connect(legendCheckBox, "onclick", this, function(e){
this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
legend.vanished = !legend.vanished;
e.stopPropagation();
});
It looks like they use the ".dijitCheckBox" class to find the checkbox dom element and connect to it using dojo/connect. Now based on that, i made this function:
function toggleSeries (legend,num) {
dojo.query("*",legend.legends[num])[0].click();
dijit.findWidgets(legend.legends[num])[0]._onClick(); }
It doesn't use any class definition (because of the *) and it accesses the areas where the checkboxes are from within the SelectableLegend. It needs the SelectableLegend and the number of the series you want to deactivate as parameters. Here the jsfiddle example with this function & hiding all 4 of your series with it:
http://jsfiddle.net/luciancd/92Dzv/17/
Also please notice the "onDomReady" Option in jsfiddle, without it: doesnt work in IE.
And the ready function within the code !
Lucian
I have updated your code http://jsfiddle.net/92Dzv/18/
Here is the key to toogle.
dom.byId(le._cbs[0].id).click();
dom.byId(le._cbs[2].id).click();
Choose the index of your legend and set to _cbs.
By this way le._cbs[0].id you will get the real id of checkbox (that inside in the widget) and then just use click()
Note : le is came from here.
var le = new Legend({
chart: chart,
horizontal: false
}, legend);