Kendo - Grid - Remove Multiple Rows - performance

I have the following code that remove rows that are checked (each row has a checkbox and I have a Filter button (and other buttons) in the toolbar).
var grid = $("#resultsGrid").data("kendoGrid");
grid.tbody.find("input:checked").closest("tr").each( function(index) {
grid.removeRow($(this));
});
However, performance starts to become an issue when there are > 20 rows being removed. However, kendo filters (removes) 20 rows or more much faster. How is kendo filtering removing multiple rows from the view? Or is there some other better way to remove multiple rows from the grid? Thanks in advance for your help.

** Updated Fiddle to new location - Same code as before **
Try dealing with the data directly. Have the checkbox hooked to the row's Id and filter on that.
I linked a fiddle that removes array elements and then re-creates the grid. The 2 text boxes at the top of the grid capture the range of Ids that you want to remove (this would be the same array of your checkboxIds). Then I cycled through those "remove Ids", removed them from the data array and remade the grid.
I slightly modified a previous fiddle and that's why I'm re-creating the grid instead of dealing with the DataSource object directly. But I hope you get the gist of what I'm doing.
I have 1000 records in this example (only 3 columns) but it removes 950 records very quickly.
Fiddle- Remove from data array
Let me know if you need an example of this with the KendoUI DataSource object.
I included this code below because StackOverflow wouldn't let me post without it.
function filterData() {
var val1 = $("#val1").val();
var val2 = $("#val2").val();
var removeIndexes = new Array();
for (var i = val1; i <= val2; i++) {
removeIndexes.push(i);
}
$(removeIndexes).each(function(removeIndex) {
var removeItemId = this;
$(randomData).each(function(dataIndex) {
var continueLoop = true;
if (this.Id == removeItemId) {
randomData.splice(dataIndex, 1);
continueLoop = false;
}
return continueLoop;
});
});
createGrid();
}

You should use batch updates:
$("#resultsGrid").kendoGrid({
dataSource: {
batch: true,
...
}, ...});
var grid = $("#resultsGrid").data("kendoGrid");
grid.tbody.find("input:checked").closest("tr").each( function() {
var dataItem = grid.dataItem(this);
grid.dataSource.remove(dataItem);
});
grid.dataSource.sync(); // this applies batched changes

Related

How to get dataItems of selectedKeyNames of checked row across all pages in kendo grid

I have Kendo grid with local data and check box and pagination. I am getting all checked items Id using selectedKeynames() across all pages.
How can I get dataItems of checked iems across all pages?
If you are using Kendo for paging, sorting and so on and not handling these operations on the server, then there seems to be no other way than skimming over the list of elements in the datasource. Something like this:
var g = $("#grid").getKendoGrid();
var d = g.dataSource.data();
var s = g.selectedKeyNames();
var r = [];
for (var i = 0; i < d.length; i++) {
if (s.indexOf(d[i].Id) >= 0) {
r.push(d[i]);
}
}
Here is a possible solution for you.
Please review the following dojo: https://dojo.telerik.com/ibALanIX
As with the other solution I am obtaining the data but using a forEach loop on the selected items as when you start having a large number of records the for loop could take some time.
So all I am doing is going over the selected items and then grabbing those items from the selected list.
var grid = $("#rowSelection").data('kendoGrid');
var selectedItems = grid.selectedKeyNames();
var actualItems = [];
if (selectedItems.length > 0) {
selectedItems.forEach(function(key) {
actualItems.push(grid.dataSource.get(key));
});
}
This would then reduce the number of loops you are having to do and as you know what the keys are from the selection, then this just uses the default get method of the kendo DataSource which maps to the ID of the model in the datasource schema.

SlickGrid CSS styles wrong on filtered view

I have a SlickGrid with dataview working pretty good, grid and dataview are synced up for modify and delete selections using syncGridSelection, however an interesting problem occurs on the changed CSS styles. The changed rows CSS stlye are being applied to the same "visible" row number in the grid when I choose a filter set that does not include the actual changed rows. The sort works fine, but I noticed that the filter is not working. Does anyone have a fix for this? Can you paste as much info and code for me as possible because I'm new to SlickGrid. I pasted code that loads up the grid.
function LoadGridData() {
$.getJSON('#Url.Action("GetConfigurations")', function (rows) {
if (rows.length > 0) {
if (rows[0].id = 'undefined') {
$(rows).each(function (index) {
rows[index].newAttribute = "id"
rows[index]["id"] = index;
});
}
};
data = rows;
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(filter);
dataView.endUpdate();
// Refresh the data render
grid.invalidate();
grid.render();
grid.setSelectedRows([]);
dataView.syncGridSelection(grid, true);
});
}
After debugging I found that I had used an older example of marking css changed in function getItemMetadata. The correct code is below. Previously I was referencing data[row]. When Syncing DataView to Grid, the getItem() method returns the correct row. In this case my DataState is my own changed indicator on the view model.
dataView.getItemMetadata = function (row) {
var item = this.getItem(row);
if (item && item.DataState == 2) {
return {
"cssClasses":
"changed"
};
}

Three level jQGrid only for some rows

I have a two level jqGrid (grid/subgrid) implementation that works very fine.
Now I have a requirement that push me to implement a third level subgrid in only some of the second level rows.
Is there any way to exclude the opening of the third level if any condition on the row does not permit it?
Thanks very much
EDIT as per #Oleg answer
I have implemented the more complex logic example as in the referenced answer, that is
loadComplete: function() {
var grid = $("#list");
var subGridCells = $("td.sgcollapsed",grid[0]);
$.each(subGridCells,function(i,value){
[...]
var rowData = grid.getRowData( ??? );
});
}
Can I use any field to retrieve the rowData in the each loop?
If I understand your question correctly you can do the same like I described in the answer, but do this on the second level of subgrids. To hide "+" icon in some rows you need just execute .unbind("click").html(""); on "td.sgcollapsed" elements of the second level subgrids.
UPDATED: The demo demonstrate how you can get rowid and use getLocalRow (alternatively getRowData) to hide selective subgrid icons ("+" icons). I used the following loadComplete code in the demo:
loadComplete: function () {
var $grid = $(this);
$.each($grid.find(">tbody>tr.jqgrow>td.sgcollapsed"), function () {
var $tdSubgridButton = $(this),
rowid = $tdSubgridButton.closest("tr.jqgrow").attr("id"),
rowData = $grid.jqGrid("getLocalRow", rowid);
if (rowData.amount > 250 ) {
$tdSubgridButton.unbind("click").html("");
}
});
}

Slickgrid add new row on demand

Is there a way to add a new row to a slickgrid on demand? For example, have a button on the page that shows the new row when clicked.
It can be done easily using dataView.addItem(params), just replace params with your parameters..
function addNewRow(){
var item = { "id": "new_" + (Math.round(Math.random() * 10000)), "Controller": tempcont, "SrNo1": tempsrno };
dataView.addItem(item);
}
here id, Controller, SrNo1 are ids of colunm
You can add a row dynamically, such as with a button click, by subscribing the "onAddNewRow" listener to your grid object. As many have suggested, it is best to use the dataView plugin to interface with your data. Note that you'll want the "enableAddRow" option set to "true".
Firstly, DataView requires that a unique row "id" be set when adding a new row. The best way to calculate this is by using dataView.getLength() which will give you the number of rows that currently exist in you grid (which we'll use as the id for the new row). The DataView addItem function expects an item object. So we create an empty item object and append the id to it.
Secondly, you'll be only focusing a single cell when you add your data. After you've entered that data (by blurring that cell), DataView will notice that you have not entered data for any of the remaining cells in the row (of course) and will default their values to "undefined". This is not really a desired effect. So what you can do is loop through the columns you've explicitly set and append them to our item object with a value of "" (empty string).
Thirdly, we don't want all the cells to be blank. Actually, we want the original cell's entered data to appear. We have that data so we can set it last so that it will overwrite the "" (empty string) value we previously set.
Lastly, we'll want to update the grid such that it displays all of these changes.
grid.onAddNewRow.subscribe(function (e, args) {
var input = args.item;
var col = Object.keys(input)[0]
var cellVal = input[Object.keys(input)[0]]
// firstly
var item = {};
item.id = dataView.getLength();
// secondly
$.each(columns, function(count, value) {
colName = value.name
console.log(colName)
item[colName] = ""
})
// thirdly
item[col] = cellVal
dataView.addItem(item);
// lastly
grid.invalidateRows(args.rows);
grid.updateRowCount();
grid.render();
grid.resizeCanvas();
});
I hope this helps. Cheers!
You can always add new rows to the grid. All you need to do is add the data object for the row to your grid data.
Assume you create your grid from a data source - myGridData (which is an array of objects).
Just push the new row object to this array. Call the invalidate method on the grid.
Done :)
Beside creating the new row, I needed it to be shown, so that the user can start writing on it. I'm using pagination, so here is what I did:
//get pagination info
var pageInfo = dataView.getPagingInfo();
//add new row
dataView.addItem({id: pageInfo.totalRows});
//got to last page
dataView.setPagingOptions({pageNum: pageInfo.totalPages});
//got to first cell of new row
var aux = totalRows/ pageInfo.pageSize;
var row = Math.round((aux - Math.floor(aux)) * pageInfo.pageSize, 0);
grid.gotoCell(row, 0 ,true);
Before I use pagination, I just needed this:
var newId = dataView.getLength();
dataView.addItem({id: newId});
grid.gotoCell(newId, 0 ,true);
var newRow = {col1: "col1", col2: "col2"};
var rowData = grid.getData();
rowData.splice(0, 0, newRow);
grid.setData(rowData);
grid.render();
grid.scrollRowIntoView(0, false);
Working fine for me.

How to append new records to existing records in a jqGrid?

I am populating Grid2 from the records selected from Grid1. however The records added are getting replaced by the new set of records from Grid1 whenever i select and add again. below is my code. This is only for the UI. I thought of appending the new records as below. Please guide with the correct code
function StuffData(data) {
var g = jQuery('#Grid2');
var usersList = data;
var totalRecords= jQuery('#Grid2').jqGrid('getGridParam','records');
alert('Grid records' +totalRecords);
if (usersList!=null) {
g.jqGrid('clearGridData',false);
for(var i=0;i<=usersList.length;i++){
// g.jqGrid('addRowData',i+1,usersList[i]);
g.jqGrid('addRowData',totalRecords+1,usersList[i]);
totalRecords += 1;
// g.jqGrid('addRowData',0,usersList);
}
}
}
The call to clearGridData is removing the old rows from the grid. From the jqGrid documentation:
clearGridData
Clears the currently loaded data from grid. If the clearfooter parameter is set to true, the method clears the data placed on the footer row.
If you only want to append data, you should be able to just remove this line of code. Or am I missing something?

Resources