Dojo DataGrid Virtual Scrolling How-To? - javascript

I've been digging around for this one quite a bit. I'm using dojox.grid.datagrid and I have an ajax call that brings back 200-300 rows.
The grid renders and scrolls just fine in Chrome but scrolling is excruciatingly slow in IE 7 and 8. I'd like to use virtual scrolling to try and remedy the issue but can't find any sample code.
Here's what my code looks like at present.
function setupAvailableScenes(location) {
var avaiableScenesGridPane = dijit.byId("AvaiableScenesGridPane");
var availableScenesGrid = dijit.byId("AvailableScenesGrid");
if (_isFirstLoad) {
availableScenesGrid = new dojox.grid.DataGrid({
id: 'AvailableScenesGrid',
store: availableScenesStore,
query: { Id: "*" },
sortInfo: "1",
rowsPerPage: 20,
autoHeight:20,
style: "width:315px",
structure: [
{ name: "Available Scenes", field: "Name", width: "85%" },
{ name: " ",
field: "_item",
rowsPerPage: "25",
type: dojox.grid.cells._Widget,
editable: false,
width: "15%",
formatter: function (scene) {
return new dijit.form.Button(
{
label: "+",
onClick: function () {
AddSceneToSelectedScenes(scene);
}
})
}
}
]
});
avaiableScenesGridPane.set('content', availableScenesGrid);
}
var availableScenesStore = new dojo.data.ItemFileWriteStore({
url: _applicationPath + "/Location/" + location.Id + "/Scene.json",
preventUrlCache: true
});
availableScenesGrid.setStore(availableScenesStore);
}

Often one of the biggest things you can do to improve DataGrid performance is to throw away the ItemFileReadStore/WriteStore and use an optimized data store (personally I like QueryReadStore). It would mean needing a server-side servlet of some kind (PHP/JSP/etc) to handle the virtual scrolling/pagination, but I've seen major perf boosts over just using a store backed by a JSON file.
Some other things to consider, which may or may not help:
give your anonymous formatter function a name and try scrolling the table with the Chrome or Firebug profiles turned on to see if it's hogging a lot of cycles (or, like Vijay Agrawal said, you could try replacing the dijit.form.Button with a vanilla html <button> tag)
you shouldn't actually need to specify the dojox.grid.cells._Widget type for that cell; having a custom formatter returning a valid Dijit should be sufficient to make the Grid do the right thing.

Since you specified rowsPerPage=25, it is already doing virtual scrolling (it pulls the new set of rows only when user scrolls down)
Since you mention scrolling is very slow, the performance issue seems to be around rendering the new rows - you may try a couple things to improve performance:
1) remove autoHeight attribute. Instead, specify a fixed height in the style attribute
2) in the formatter function, instead of returning a dijit, try returning a simple html button/anchor styled as button
so remove the type:dojox.grid.cells._Widget attribute and in the format function return the html you want to use

Related

$.fn.dataTableExt.aoFeatures.push change setting

I have below code
$.fn.dataTableExt.aoFeatures.push({
"fnInit": function (oSettings) {
oSettings.oScroll.sY = 5;
return { "oSettings": oSettings } ;
},
"cFeature": "T"
});
$.extend($.fn.dataTable.defaults, {
//"scrollY": 5,
"dom":"T"
});
I can see scrollY changed in function but no effect in datatable, How can overwrite the default setting using this function, since i have to put condition ono tableid,
otherwise I could have done below way which is working
$.extend($.fn.dataTable.defaults, {
"scrollY": 5,
});
I believe I am missing something on return statement which will override the things
fiddle reference
You code is not working for a few reasons. First, you are using an outdated API. $.fn.dataTableExt.aoFeatures.push is the old API used with $(...).dataTable(). By using $(...).DataTable() (note the capital "D") as you did in your fiddle, you are choosing to use the new API. (Read about converting code using the old API to use the new API here.) Using the current API is a great choice, but you then need to use $.fn.dataTable.ext.feature.push to set up your feature.
This works:
$.fn.dataTable.ext.feature.push({
"fnInit": function (settings) {
settings.oScroll.sY = 25;
},
"cFeature": "T"
});
However, the dom feature is intended to indicate the order of elements in the table. Using it to set style like scrollY is OK, but not exactly what they had in mind. The point being that if you are going to specify dom at all, you have to specify all the elements you want. In particular, you have to specify t for table or else the DataTable will not attach itself to the table at all. So you need to set up your table with something like this to trigger your scrollY "feature":
$(document).ready(function() {
var table = $('#example').DataTable({
"dom":"Tlftip"
});
Note that the order matters. The "T" has to come before the other elements that are affected by the changes made in the feature. "dom":"lftipT" will not have the desired effect.

Extjs 4 grouped columns header dynamic text modification

I have the following grouped headers grid :
var lestore = Ext.create('Ext.data.Store', {
proxy: {
type: 'memory'
},
autoDestroy: true,
data:objstore
});
thegrid = Ext.create('Ext.grid.Panel', {
store: lestore,
columnLines: true,
columns: [{text:'date'},{text:'TV',columns:{text:'400',columns:[{text:'tt1'},{text:'tt2'}]}] ,
title:'my title' ,
selModel: {
selType: 'cellmodel'
},
renderTo: 'gridmpoff',
plugins: [Ext.create('Ext.grid.plugin.CellEditing', {clicksToEdit: 1}
)
],
listeners: {'edit': function(editor,e) {updtitle(editor,e);}
},
viewConfig: {
stripeRows: true
},
});
I need to change the columns texts (tt1,tt2 etc) after the grid creation, without changing the header grouping.
I Tried modifying the columns property, but that doesn't help, only thing that worked so far is a reconfigure which messes with the editor.
Please advice
ExtJS provides setText method fo changing the header text.
Refer http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.column.Column
After so many searches i came up to the idea that ExtJS 4.1 "reconfigure" is buggy and has never been fixed, as it messes with the plugins (the editor in particular), and every fix i found so far targets only a particular use case, mine was just updating the grouped headers labels without touching anything else.
The solution i used is to simply update the dom (while at same time update the columns headers structure for the extjs so that if at some point their bugs are fixed it is simple to switch to reconfigure, settext or whatever), via : thegrid.container.dom.childNodes ....
I hope this helps gettings someone else from this struggle.
This is related : Using Ext.grid.Panel.reconfigure() breaks the grids RowEditing plugin
Try below code:
grid.columns[0].ownerCt.setText('Total Number');
I know this is an old thread but you can use the code Michael posted :
grid.columns[0].ownerCt.setText('Total Number');
and then use the column name in your groupHeaderTpl and have something like this :
{columnName}: {name}
This way it will dynamically change it to the values you want.

pagination not working for KO Grid

I am working with KO-grid and it seems to load all the data fine. Now, I am working on the pagination part and it does not seem to work properly. Yes, I do the pagination control on the bottom but when it comes to be able to decide the page size, it does not seem to work. The page size is driven by two options according to confguration details given on https://github.com/ericmbarnard/KoGrid/wiki/Configuration
1.pageSizes:[5,10, 25] -- seems to show options but when I change my selection from 5 to 10 then it does nto seem to work upon the choices.
2.pagesize ://somenumber -- breaks the code.
I have working model of it on jsfiddle: http://jsfiddle.net/sf4p3/46/
Any suggestions?
Well, it appears that the pagination in KoGrid doesn't work the magic that you were hoping for.
Here's a link to the example from the KoGrid wiki on GitHub:
http://ericmbarnard.github.com/KoGrid/examples/Complex-Server-Side-Paging.html
In viewing source for the HTML page, one will likely see the beginning of the view model declaration without having to scroll (depending on screen resolution, of course). Regardless, this starts around line 30.
Notice that there is an observable named pageSize in the view model, and it is set to 50.
Scrolling down a bit, one should see functions named filter, sort, and getPagedDataAsync for filtering the data, sorting the data, and creating the data set for the current page.
Here's the code for the getPagedDataAsync function:
this.getPagedDataAsync = function (pageSize, page, filterInfo, sortInfo) {
setTimeout(function () {
var data = window.getExampleData();
var filteredData = filter(data(), filterInfo);
var sortedData = sort(filteredData, sortInfo);
var pagedData = sortedData.slice((page - 1) * pageSize, page * pageSize);
self.myObsArray(pagedData);
}, 0);
};
Without seeing the details of the rest of the view model, one should be able to tell from reading the above code that this function starts by retrieving all data to be displayed for this example page, then filters the data and sorts the data.
After that, the data array is sliced to extract the data to be viewed for the current page, and that slice is passed to the myObsArray observable array that is used to display the data in the grid.
Here's the declaration of the grid in this example:
<div id="sandBox" class="example" style="height: 600px; max-width: 700px;"
data-bind="koGrid: {
data: myObsArray,
columnDefs: [
{ field: 'Sku', width: 140 },
{ field: 'Vendor', width: 100 },
{ field: 'SeasonCode', displayName: 'Season Code', width: 150 },
{ field: 'Mfg_Id', displayName: 'Mfg ID', width: 180 },
{ field: 'UPC', width: 170 }
],
autogenerateColumns: false,
isMultiSelect: false,
enablePaging: true,
useExternalFiltering: true,
useExternalSorting: true,
filterInfo: filterInfo,
sortInfo: sortInfo,
pageSize: pageSize,
pageSizes: [25, 50, 75],
currentPage: currentPage,
totalServerItems: totalServerItems,
selectedItem: selectedItem }">
</div>
Hopefully, this helps, and you'll be able to fix your paging issues.
Regardless, please let me know if you have any questions.
UPDATE
#Californicated I'm on vacation, but I had some downtime to take a peek at your latest fiddle.
I forked what you had in your latest fiddle and made the following changes to get the paging to work:
In the declaration of observables, I changed the value of pageSize to 2 and the value of totalServerItems to 7.
In the JS, I changed the declaration of the data var in the
getPagedDataAsync function so it's retrieving the
Prizefillfilmentstatuses observable array.
On the last line of the JS code, I changed the first parameter from 50 to 2.
In the jsFiddle toolbar, I changed the first dropdown from "onLoad" to "no wrap (body)"
In the declaration of the koGrid in the HTML, I added the following options/parameters:
pageSize: pageSize,
currentPage: currentPage,
totalServerItems: totalServerItems,
selectedItem: selectedItem
The page setup was working with the JS changes, alone, but the paging tool (previous, next, etc.) was not active until I added the totalServerItems option in the koGrid declaration.
Again, let me know if you have any questions.

Javascript InfoVis Spacetree - Dynamically hide/show Tooltips

I've been googling this and can't seem to find an answer. I will also ask this in the JavaScript InfoVis Toolkit Google Group.
I was wondering if it's possible to dynamically hide/show tooltips using InfoVis spacetree. Currently they are turned on and I have set up the tips like this:
Tips: {
enable: true,
type: 'HTML',
offsetX: 10,
offsetY: 10,
onShow: function (tip, node)
{
tip.innerHTML = getToolTip(node);
}
},
but I can't seem to find any references for how I might turn them off later. For example, I want the user to be able to check a box to hide/show Tooltips and then display them accordingly. I tried st.tips.hide() (st is the name of my spacetree) but it doesn't do anything. If I do alert(st.tips) I get an object but I don't know what functions are available on the object.
Any help would be much appreciated! Thanks!
I'm using ForceDirected and had a similar problem. I wanted to keep the tooltip displayed for a certain period of time after the user leaves the node with the cursor...
Calling
graph.tips.hide(false)
works for me (did you ever try passing an argument to hide?).
I can't tell you whether to pass true or false, they both work for me...
Overall you could try something like:
Tips: {
enable: true,
type: 'HTMl',
onShow: function(tip, node, isLeaf, domElement) {
//Check if checkbox is checked
var checked = $('input[type=checkbox]').is(':checked');
if (checked == true){
tip.innerHTML = getToolTip(node);
} else {
graph.tips.hide(true);
};
}
In any case this is just an idea and I don't have the time to test it (pseudocode?..)
Hope this helped!
Cheers

Change JavaScript object values with auto-generated HTML form

I have got a 'big' JavaScript object that looks somewhat like this:
var userConfig = {
active: true,
subElement: { someProp: 156, otherProp: 'yaye' },
foo: ['bar', 'see', 'no']
// etc
}
What I'm looking for is some sort of framework that I pass the variable (or a part of the variable) to and that reads all properties and creates a form where these can be configured. So a checkbox would be created for a boolean, a textbox for a string etc...
Anyone knows about such a library?
Update: At the moment settings are changed by opening the JS and editting the variables manually (The JS is a locally stored greasemonkey script). Pretty much anything beats that really.
I'm not interested in writing (alot of) code to do two way binding, creating all the UI widgets and having a clean seperation of concerns (MVVM, MVP, ...) which is what Knockout/Backbone/... does (judging from the tutorials).
Instead:
var userConfigUpdater = {
active: { description: "Activates or deactivates feature X", editType: "boolean"},
subElement: {
description: "subElement",
editType: "tabularItem",
someProp: {description: "foo", editType: "text"},
// more
}
}
createHtmlWidgets(userConfig, userConfigUpdater);
Now the user can edit the form elements and then we have something like:
$("#okButton").click(function() {userConfig = getUpdatedValues();});
Granted, it doesn't look very nice, but it would get the job done quite fast/easily. I'm guessing there is not yet some public framework that does something like this?
The closest thing I know is knockoutjs. This doesn't do exactly what you want but what it does do is allow a mechanism for keeping that object in the knockout world it would be called a viewModel in sync with your form so if you update the form contents it would update that object's data automatically and vice-versa
I ended up writing my own 'framework'.
It is 'pretty' generic but somewhat integrated into the rest of my project, really limited in features and the API is not very clean. Use at your own risk :)
The source code on GitHub. The 'framework' is propui.js and sangu_config.js is the configuration for propui.
Example how to call the API:
backgroundColor: {
label: "Change the background color",
propUI: {
getter: function() { return settings.backgroundColor; },
setter: function(value) { settings.backgroundColor = value; },
editor: "bool"
}
},

Categories