I have a grid with a default sorted on a column and I'm having problems getting the next/previous rows by adding or substracting from the currently selected row ID.
Here's the column with the default sort
{
headerName: "Created",
field: "createdOn",
cellRenderer: (params) => {
return WebModule.Utils.dateFormat(params.value);
},
sort: "desc",
width: 125
},
And here's my logic to get previous/next row
class ResultModal {
constructor(params) {
this.params = params
let rowIndex = params.rowIndex;
this.previousRow = params.api.getRowNode(rowIndex - 1);
this.nextRow = params.api.getRowNode(rowIndex + 1);
this.result = params.data;
}
}
I pass the whole ag-grid params object to a modal so I can navigate the grid records from buttons in the modal.
The issue is that if I run the above logic with the 2nd row selected, params.rowIndex is 1, I get nextRow with (1+1) but the actual rowIndex of nextRow will be something like 2245 (I have lots of data in the grid).
So I end up selecting a row burried deep down in the grid instead of the actual 3rd row displayed.
Do I need to use something else than getRowNode when the grid is sorted/filtered ?
I ended up using api.getDisplayedRowAtIndex()
let node = params.api.getSelectedNodes()[0];
let rowIndex = node.rowIndex;
this.previousRow = params.api.getDisplayedRowAtIndex(rowIndex - 1);
this.nextRow = params.api.getDisplayedRowAtIndex(rowIndex + 1);
This really gets the previous and next row regardless of the sort/filter options.
One possible solution might be to use
gridOptions.api.forEachNodeAfterFilterAndSort
which iterates over the rows as they are displayed. Note that the callback passes the RowNode itself and the row-index in the grid.
function forEachNodeAfterFilterAndSort(
callback: (rowNode: RowNode, index: number) => void
): void;
https://www.ag-grid.com/javascript-data-grid/grid-api/#reference-rowNodes
Related
Logic of my page in a nutshell:
.csv file uploads (I have an array in code so I don't need to upload it every time)
code receives array from this .csv file that consists of [array, headers], where array - csv file data and headers - the first line of csv file and then it converts into object[]
after clicking on submit button selection table appears where you can choose which columns will be static, and others will be dynamic, so if f.e. you have 20 columns in file, you choose 3 static columns, and the rest is building with arrows that will change 'table page' (Everything can be seen in result and console)
I've separated columns so I can call data by index from array:
I have array: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
After it is being separated: [['h1', 'h2'], ['h3', 'h4'], ['h5', 'h6]]
My logic of building a table is creating two arrows and set initial index to 0. Right arrow will do index++ and left arrow will do index--.
When building a table, I can do like:
const headers = [['h1', 'h2'], ['h3', 'h4'], ['h5', 'h6]]
let tableIndex = 0
/* code with index++ and index-- */
arr.forEach(obj => {
const dynamicTableRow = document.createElement('tr')
headers[tableIndex].forEach(header => {
const dynamicTableDataCell = document.createElement('td')
dynamicTableDataCell.innerHTML = obj[header]
dynamicTableRow.appendChild(dynamicTableDataCell)
})
dynamicTableBody.appendChild(dynamicTableRow)
})
So the array that I actually need will be called by index - headers[tableIndex]
Full working code is here:
Updated codepen - here
My question is: how to make index change by clicking on buttons?
I had 2 variants how to make it:
Add onclick functions to buttons, but I don't really understand how to make it correctly and workable
Import buttons to js code, and do like
buttonPrevious.onclick = () => {
tableIndex--
/* render table with updated index */
}
buttonNext.onclick = () => {
tableIndex++
/* render table with updated index */
}
But this method is really not good, because I will render table 3 times - after headers selection and after click on one of the buttons
So the answer is much easier than I thought. I placed my dynamic table render into a function, and then created 2 eventListeners for each button.
Full working code is on codepen in the question
buttonPrevious.onclick = () => {
const copy = [...dynamicTableKeys]
const headers = getSplicedHeaders(copy)
console.log(dynamicTableKeys)
console.log(headers)
if (tableIndex === 0 && tableIndex > -1)
tableIndex = 0
else
tableIndex--
renderDynamicTable(tableIndex, dynamicTableKeys, headers)
}
buttonNext.onclick = () => {
const copy = [...dynamicTableKeys]
const headers = getSplicedHeaders(copy)
console.log(dynamicTableKeys)
console.log(headers)
console.log(tableIndex)
if (tableIndex === headers.length - 1)
tableIndex === headers.length - 1
else
tableIndex++
console.log(tableIndex)
renderDynamicTable(tableIndex, dynamicTableKeys, headers)
}
I am using ag-grid in raw javascript (ie- no angular, no jquery). The grid shows streaming data and dynamically updates with new rows as they come in. My goal is to highlight rows that are less than 20s old in a different color.
I can easily apply css classes on a row-by-row basis when they are initially rendered, but I can't figure out how to remove the css classes when they become older than 20 seconds. Here is what I am doing:
class TickerController {
constructor() {
...
this.gridOptions = {
rowClass: 'ticker--row',
rowClassRules: {
'-new-row': params =>
(Date.now() - params.data.accepted_time) < NEW_ROW_THRESHOLD
}
};
let tickerGrid = this._getElementById('ticker-grid');
new agGrid.Grid(tickerGrid, this.gridOptions);
}
...
}
You can see here that I am applying a ticker--row class to all rows and a -new-row class to rows that are new. This does highlight new rows, but I don't know how to re-apply the rowClassRules on a periodic basis.
Can someone explain the proper way to achieve my goal of removing the -new-row class when the row is no longer new?
plunker for demonstration
Here is one way that it could be done:
have a data value in the row to hold the information of whether or not to highlight the row
define the rowClassRules to look at that data value
when a new row is added, create a timeout to trigger in 20 seconds to update this value.
var gridOptions = {
...
rowClassRules: {
'highlight': 'data.lessThan2'
}
...
};
function onInsertRowAt2() {
var newItem = createNewRowData();
var res = gridOptions.api.updateRowData({add: [newItem], addIndex: 2});
printResult(res);
setTimeout(updateItems,2000,res)
}
function updateItems(rows) {
var updatedRows = rows.add.map(row => row.data)
updatedRows.map(e=>e.lessThan2 = false)
gridOptions.api.updateRowData({update: updatedRows})
}
We have an operation in our Hands on table app that assigns a format to columns via a drop down as demonstrated here:
http://docs.handsontable.com/0.16.1/demo-custom-renderers.html#page-dropdown
When a new format is picked, we apply the formatting to the column.
columns[i].type = type;
instance.updateSettings({columns: columns});
What I need to do is exclude the first row from this type of column update as it is a static text field which should not be changed. Is there an example of this available?
According to the documentation, the cells option takes precedence over columns. So what you could do is set cells to the following:
cells: function(row, col, prop) {
var cellProperties;
if (row === 0) {
cellProperties = {
type: 'text' // force text type for first row
};
return cellProperties;
}
}
What this will do is set a type to the first row. Now when you update columns, it won't apply to the first row because cells is taking precedence.
I am struggling trying to find the right method to do this. Basically, I have an array of id values that correspond to which rows have been selected in my table. To construct this list, I use the following code. this.options.ajaxId is the key that accesses my Id value in the data object passed to the table.
this.getRowData(target)[this.options.ajaxId]
where my getRowData function is:
getRowData: function (HTMLrow) {
return this.dataTable.row(HTMLrow).data();
},
This works great, but then I am stumped on my next step which is re-selecting the correct rows when the table is re-drawn via paging, sorting, or searching. My plan was to cycle through the ID's and find which table row corresponded to that ID value, but I cannot find a function to input a key value search pair and return the html row. Something like the following is what I was thinking,
this.dataTable.findRow( key, value );
// then my usage would be the following:
var that = this;
_.each(this.selectedList, function (id) {
var row = that.dataTable.findRow( that.options.ajaxId, id );
// code to select the row
});
I haven't written it yet, but I know I can cycle through each of the rows, get the data for that row, and check it against what I am looking for, but in cases where the user is viewing 100 rows and has only one selection I would like to avoid that.
Any insight?
Thanks
SOLUTION #1
You can use the following code to locate and highlight rows based on row IDs if row ID is stored in one of the fields.
// Index of column containing IDs
var colIdIndex = 0;
// List of row IDs
var rowIds = ['2', '4', '6'];
// Find indexes of rows which have IDs in the desired column
var rowIndexes = table.rows().eq(0).filter( function (rowIdx) {
return ($.inArray(table.cell( rowIdx, colIdIndex ).data(), rowIds) !== -1)
? true
: false;
});
// Select rows based on array of found row indexes
table.rows(rowIndexes)
.nodes()
.to$()
.addClass('selected');
See filter() API method for more details.
Please note that this method will work for client-side processing mode only.
DEMO
See this jsFiddle for code and demonstration.
SOLUTION #2
Alternative approach that would work both in client-side and server-side processing modes would be to use createdRow callback.
For example:
// Index of column containing IDs
var colIdIndex = 0;
// List of row IDs
var rowIds = ['2', '4', '6'];
var table = $('#example').DataTable({
createdRow: function( row, data, dataIndex ) {
if ( $.inArray(data[colIdIndex], rowIds) !== -1) {
$(row).addClass('selected');
}
}
});
DEMO
See this jsFiddle for code and demonstration.
I am using jqgrid in 'multiselect' mode and without pagination. When the user selects individual records by using mouse click, is there any way that I can bring those selected records to the top of the grid?
Thanks in advance for your help.
After small discussion with you in comments I could reformulate your question so: "how one can implement sorting by multiselect column?"
The question find is very interesting so I invested some time and could suggest a solution in case of jqGrid which hold local data (datatype which is not 'xml' or 'json' or which has 'loadonce: true' option).
First of all the working demo which demonstrate my suggestion you can find here:
The implementation consist from two parts:
Making selection as part of local data. As the bonus of the selection will be hold during paging of local data. This feature is interesting independent on the sorting by multiselect column.
The implementation of sorting by multiselect column.
To implement of holding selection I suggest to extend local data parameter, which hold local data with the new boolean property cb (exactly the same name like the name of the multiselect column). Below you find the implementation:
multiselect: true,
onSelectRow: function (id) {
var p = this.p, item = p.data[p._index[id]];
if (typeof (item.cb) === "undefined") {
item.cb = true;
} else {
item.cb = !item.cb;
}
},
loadComplete: function () {
var p = this.p, data = p.data, item, $this = $(this), index = p._index, rowid;
for (rowid in index) {
if (index.hasOwnProperty(rowid)) {
item = data[index[rowid]];
if (typeof (item.cb) === "boolean" && item.cb) {
$this.jqGrid('setSelection', rowid, false);
}
}
}
}
To make 'cb' column (multiselect column) sortable I suggest to do following:
var $grid = $("#list");
// ... create the grid
$("#cb_" + $grid[0].id).hide();
$("#jqgh_" + $grid[0].id + "_cb").addClass("ui-jqgrid-sortable");
cbColModel = $grid.jqGrid('getColProp', 'cb');
cbColModel.sortable = true;
cbColModel.sorttype = function (value, item) {
return typeof (item.cb) === "boolean" && item.cb ? 1 : 0;
};
UPDATED: The demo contain a little improved code based on the same idea.
If you have the IDs of the row(s) you can do a special sort on server side by using following command for e.g. MySQL:
Select a,b,c
FROM t
ORDER BY FIND_IN_SET(yourColumnName, "5,10,44,29") DESC
or
ORDER BY FIELD(yourColumnName, "5") DESC