UI Grid Poor Vertical Scroll Performance - angularjs

I'm using the new Angular UI Grid v3.0.7 and have an issue regarding vertical scrolling when using a custom cell template. My grid had 15 columns with 83 rows so it's not a large data set. My cell template is simply a span that has a class which adds either a checkmark or a cross (e.g. IcoMoon) based on a boolean. The cell template is fine when applied to a single column but rapidly deteriorates when adding more than 3. I have to apply it to 13 columns. Here is the cell template function:
function checkCrossCellTemplate() {
return '<span ng-class="{\'icon-checkmark\': row.entity[col.field]===true, \'icon-cross\': row.entity[col.field]===false}"></span>'
}
I think the issue relates to the condition being applied as it's killing the smooth scrolling, I've also tried a different approach using ng-if but the performance issue still stands. To prove my theory I've come up with another function:
function checkCrossCellTemplate() {
if(Math.random() <= 0.5 ) {
return "<span class='icon-checkmark'></span>"
} else {
return "<span class='icon-cross'></span>"
}
}
This is obviously a contrived example but solves the vertical scrolling issue.
Has anyone encountered this problem? Are there any workarounds?

I got around this performance issue by providing a cell class instead of a cell template. To be honest the first approach should of worked, it rendered the fonts correctly but you couldn't smoothly scroll.
function myCellClass(grid, row, col, rowRenderIndex, colRenderIndex) {
var value = grid.getCellValue(row, col),
cellClasses = [];
if(typeof value === 'boolean') {
if(value) {
cellClasses.push('icon-checkmark');
} else {
cellClasses.push('icon-cross');
}
}
if(rowRenderIndex % 2 !== 0) {
cellClasses.push('table-row');
}
return cellClasses.join(' ');
}

Related

How to optimize mouseover function's current logic to improve performance

I have 2 series (lines) displayed as shown in demo. I can have up to 30 series (lines) in one go.
What is implemented is, as soon as I move the mouse, it should update the current value (for all series (lines) - remember I can have up to 30 series in one go) in the grid shown right below stock chart. It is working as expected.
Pls find working demo : https://stackblitz.com/edit/react-ts-qcsum9?file=stockchart%2Fstockchart.js,constants%2Fzoom-level.js,stockchart%2FchartOptions.js
FYI: You can focus on only mouseOver function rather than looking in to all other files as demo has so many files.
Problem : Problem related to performance
As I told you I can have up to 30 series (lines) in one go. In given demo, there are two series(lines) and when you select 30 days, you have to move your mouse slowly in other to see updated or current hovered value in the gird. If you move your mouse speedily, it will not update the value immediately (I think that is obvious).
But the problem is on each mouse move, I'm looping through all available lines multiple times and perform some logic. I know it is a bit complex logic as shown in below code snippet. It runs every time when mouse is moved for each hovered point for all the lines. This is very bad way of updating the current value.
I know this is not the correct implementation but I really have NO IDEA how to optimize it. Any help would be greatly appreciated.
Code: Select all
point: {
events: {
mouseOver: (e) => {
const xAxisValue = e.target.x;
const chart = e.target.series.chart;
const series = chart.yAxis[0].series;
const totalGridSeries = [...stockGrid];
for (let i = 0; i < series.length; i++) {
const name = series[i].name || series[i].name;
const foundSeries = totalGridSeries.find(
(x) => x.name === name
);
if (foundSeries) {
if (xAxisValue) {
const foundPoint = series[i].points.find(
(t) => t.x === xAxisValue
);
if (foundPoint && foundPoint.y) {
foundSeries.currentValue = foundPoint.y;
} else {
foundSeries.currentValue = undefined;
}
} else {
foundSeries.currentValue = undefined;
}
}
}
setStockGrid(totalGridSeries);
},
},
}

How to get global index in devexpress datagrid with ReactJS

I'm working with DevExpress DataGrid on React.js.
According to this example, I can navigate to specific row that not visible within a specific key.
But in this example, it use the "focusedRowKey" property.
In my case, I use the "focusedRowIndex" property. My problem is that I want to navigate to specific row by index that is not visible.
Is there any "navigateToRow" function that receive index, and not key?
Or can I get the global index, like "getRowIndexByKey" (this function not good for me, if the index is outside the visible rows, it return -1).
Thanks.
Solved it by manipulating between them:
let value = null;
// eslint-disable-next-line default-case
switch (fieldType) {
case 'focusedRowIndex':
value = eventIndex;
break;
case 'focusedRowKey':
value = eventId;
break;
}
const obj = {
[fieldType]: value
};
And then, on the component itself:
<DataGrid
id='grid-container'
dataSource={events}
keyExpr='_Id'
showBorders={true}
focusedRowEnabled={true}
{...obj}

Programmatically change grid column order

I want to sort the columns in my grid, just like the rows. I have made a simple sort function that is called from an actioncolumn handler:
sortColumns:function(record) { // The record after which's values the columns are ordered
var columns = this.columns;
Ext.Array.sort(columns,function(col1,col2) {
if(record.get(col1.dataIndex) > record.get(col2.dataIndex)) return 1;
if(record.get(col1.dataIndex) < record.get(col2.dataIndex)) return -1;
if(col1.dataIndex > col2.dataIndex) return 1;
if(col1.dataIndex < col2.dataIndex) return 1;
throw new Error("Comparing column with itself shouldn't happen.");
});
this.setColumns(columns);
});
The setColumns line now throws the error
Cannot add destroyed item 'gridcolumn-1595' to Container 'headercontainer-1598'
which is because the "old" columns are destroyed first, and then the "new" columns, which are the same and thus destroyed, are applied.
I only want to change the order, but I didn't find any function to do it. Do you know how to do it?
Drag-drop ordering of the columns works, so it is doable; but I don't find the source code where sencha did implement that drag-drop thingy. Do you know where to look for that code?
Reconfigure method needs two arguments
grid.reconfigure(store, columns)
Here is the fiddle that changes the columns programatically https://fiddle.sencha.com/#fiddle/17bk
I have found that columns are items of the grid's headerCt, so the following works well, and unlike the other answers, it does not create new column components, keeping the column state and everything:
var headerCt = normalGrid.headerCt,
columns = headerCt.items.getRange();
Ext.Array.sort(columns,function(col1,col2) {
if(record.get(col1.dataIndex) < record.get(col2.dataIndex)) return -1;
if(record.get(col1.dataIndex) > record.get(col2.dataIndex)) return 1;
if(col1.dataIndex < col2.dataIndex) return -1;
if(col1.dataIndex > col2.dataIndex) return 1;
return 0;
});
headerCt.suspendLayouts();
for(var i=0;i<columns.length;i++)
{
headerCt.moveAfter(columns[i],(columns[i-1] || null));
}
headerCt.resumeLayouts(true);
There is a reconfigure method which can be used to achieve reordering, e.g:
grid.reconfigure(columns);
Check the this.
I couldn't manage to do it without storing columns in a custom field and using reconfigure, maybe someone can suggest something better (reconfigure doesn't work well with just regular columns field it seems):
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
//just renamed "columns"
myColumnConfigs: [
//all your column configs
]
});
//to rearrange inside controller, also need to call it on grid render
var grid = this.getView();
var columns = grid.myColumnConfigs;
//...do your sorting on columns array
grid.reconfigure(columns);

ui-grid infinite scroll with row processor filtering

I have an angularjs app using ui.grid with the infinite scrolling module. I am using whole row filtering as described in the documentation like so:
function MyController($scope){
var that = this;
var getData = function(){
//logic left out for brevity
};
var onRegisterApi = function(gridApi){
gridApi.grid.registerRowsProcessor(function (rows) {
return that.filterRowProcessor.apply(that, [rows]);
}, 200);
gridApi.infiniteScroll.on.needLoadMoreData($scope, getData);
};
this.options["onRegisterApi"] = onRegisterApi;
}
//...code excluded for brevity...
MyController.prototype.filterRowProcessor = function(renderableRows){
renderableRows.forEach(function(row) {
if (this.selectedMap[row.entity["Id"]]) {
row.visible = false;
}
});
return renderableRows;
}
The idea is to filter out rows which have an Id belonging to a specific collection; which works as designed. My problem is that when I get my first page of data the filter row processor removes enough rows from visibility that my scroll bar disappears. This in turn causes the infinite scroll api to never raise the "needLoadMoreData" event.
Is this uncharted territory, or is there a way around this? I am also open to not filtering by that mechanism if its easier to do another way.
UPDATE (01/08/2016)
I have found a work around that I don't like very much. Essentially I have a known page size and if the data coming in to the grid is less than that page size and my callback returns false for "end of query", I automatically issue a next page query. I would rather find a solution via the grid api, but for now this will work.
if(this.itemsSource.data.length < constants.PAGE_SIZE && !continuation.endOfQuery){
//call get data again
}
After thinking about it for a while I decided on the below method as my solution. I am still open to suggestions if it makes more sense to do it a different way. Rather than relying on a length of data (which only loosely translates to having a scroll bar) I decided to calculate the height of the total rows visible, compared to the viewport of the grid.
//this method get called from the callback from needsMoreData
//hasMoreData is the same boolean flag sent in to dataLoaded
var shouldRetrieveMore = function (gridApi, hasMoreData){
if (!hasMoreData) {
return false;
}
var totalCountOfRows = gridApi.grid.getVisibleRowCount();
if (totalCountOfRows === 0) {
return true;
}
var height = gridApi.grid.getViewportHeight();
var heightOfRow = gridApi.grid.getVisibleRows()[0].$$height;
return ((heightOfRow * totalCountOfRows) <= height);
}
One additional addendum to the solution could be to sum the $$heights of all the rows, but I decided against it since in my uses they are always the same height.

How to count number of rows in sencha gridview?

I have a Gridview on my page and I'm using buffered store. Is there a way to get the visible number of row count. Thank you
Here is a sample code that you can try: (I hope you'll get some idea from this)
// The below condition has to be checked for each record
// record: record instance
var me = this; // grid scope
Ext.Array.each(me.columns, function (item) { // iterate through each column in the grid
if (item.hidden || !item.dataIndex) { // you can avoid hidden columns and one's that re not bound to the store
return;
}
var cellVal;
try {
cellVal = Ext.fly( me.view.getCell(record, item)).select('cell selector class').elements[0].innerHTML;
} catch (e) {
// handle if you want
}
if (!Ext.isEmpty(cellVal)) {
// this record has been rendered
}
}, this);
This will get you all the records that are rendered. Since you are using a bufferedRenderer, this will also return the records that are rendered but not in the view, you can check and put an offset for the buffer.
Note: I've a similar logic in working in ExtJs 5 but haven't tested in touch.

Resources