How to get a node by index in ag-grid? - javascript

AgGrid expects node(s) to be passed in to lot of it's data functions. How do you get a node by index? Look at the snip below:
api.forEachNode(function(node){
api.refreshRows([node]);
})
I can pass the node parameter to refreshRows() function since I'm getting it through forEachNode().
How do you get a node by index without iterating through forEachNode() ?

This might be a bit late for this question, but anyway for people who are searching for this in the future :
Apart from the answers given, you can also get the row node by using the following ways,
// Getting the row node by the row index
cont rowNode1 = api.getDisplayedRowAtIndex(rowIndex);
In some cases, the above approach is not suitable because the rowIndex can get changed when you do some changes to your grid (sort, filter, etc.).
The other method is to use the id of the row which will not change even if you sort, filter... the grid.
getRowNode(id) : Returns the row node with the given ID. The row node id is the one you provided with the callback getRowNodeId(data), otherwise, the id is a number auto-generated by the grid when the row data is set.
// Getting rowNode by row id
const rowNode2 = api.getRowNode(rowId);

You can use getVirtualRow() method to get a single row. This function is a part of the Row Model. You can get the Row Model by getModel() function.
var model = api.getModel();
console.log(model.getVirtualRow(idx));

Building on #Charlie H's answer, it's entirely possible that since the version that he was using, the API has changed a bit. I'm using the (current as of December 2017) version 15.0. I found that rowsToDisplay[] contains an array of rows accessible. The following, for example, does exactly what you'd think it would:
onCellEditingStarted: function (event) {
var displayModel = gridOptions.api.getModel();
var rowNode = displayModel.rowsToDisplay[event.rowIndex];
rowNode.setRowHeight(100);
gridOptions.api.onRowHeightChanged();
},

If you want to iterate through the grid row by row in order you can use this (where $scope.grid is your grid name):
$scope.high_index = 0;
$scope.rows = [];
$scope.grid.api.forEachNode(function (node) {
$scope.rows[node.childIndex] = node.id;
if (node.childIndex > $scope.high_index)
$scope.high_index = node.childIndex;
});
for (i = 0; i <= $scope.high_index; i++) {
var node = $scope.grid.api.getRowNode($scope.rows[i]);
}
Or if you want a row node by child index you can now use (after setting up $scope.rows above):
var node = $scope.grid.api.getRowNode($scope.rows[i]);
Where i is the row number you want.

Related

getRange() with specific criteria in Google Apps Sheets Script

I'm very new to JavaScript, and have only recently started fiddling with coding.
I had found a question that is similar to what I'm asking, so I've tried to modify the suggestions to fit my needs, but am drawing a blank pulling together other resources to understand the solution.
That question and answer is here: range.getValues() With specific Date in Specific Cell
I hope to ask my question by adding it to that thread, but I'm unable to make a comment - only an Answer, as I have zero votes.
I want to know how I can use the range.setValues() function, but specify only rows of cells that fit a certain criteria (e.g. cell in column B = 1).
Mostly I understand the answer, I think - push the full list of data into another array, then use a for loop to identify which rows to "keep".
However, I don't understand a good chunk of the solution, specifically this portion:
data.forEach(function(row) {
var colHvalue = row[7];
var colKvalue = row[10];
if( /* your desired test */) {
// Add the name of the sheet as the row's 1st column value.
row.unshift(sheetName);
// Keep this row
kept.push(row);
}
});
where I'm confused:
What's function(row) refer to? It seems to me that "row" is not a defined variable, and is also not a method.
What are the objects being specified in the line var colHvalue = row[7];? And same for the second row.
How does the pushing and unshifting work?
Hope for some answers, thanks!
Edit:
So I still don't understand the detailed logic of the Answer to that other question, and wrote something else based off that:
function importtest() {
var sheetX = SpreadsheetApp.openById("XXX-XXX-XXX"); // workbook containing orginal data
var tabX = sheetX.getSheetByName("EXPORTER"); // tab containing original data
var rangeX = tabX.getRange(6,2,sheetX.getLastRow(),sheetX.getLastColumn()).getValues(); //range of full original data
var kept = [] ;
var data = rangeX ; //storing full data in "data"
// define function "latestrows", which fills up the "kept" array with selected rows
function latestrows() {
var datesent = data[i][2] ; // indicating dynamic cell position (using variable i) that determines if should be kept or not
var datarow = data[i] ; // specify the entire row of data
// loop statement; starting with i=0 (or row 1), and increasing until the last row of "data"
for ( i = 0; i < data.length ; i++) {
if (datesent == 1) { // if cell in the col indicating if it should be kept, is "1"
kept.push(datarow); //move the chosen rows of data into "kept"
}
}
}
var sheetX3 = SpreadsheetApp.openById("XXX-XX-XX"); // workbook import destination
var tabX3 = sheetX3.getSheetByName("IMPORTED"); // import destination tab
var rangeX3 = tabX3.getRange(7,3,kept.length,kept[0].length) // imported array range
rangeX3.setValues(kept); // set values
}
I get the error message TypeError: Cannot read property "length" from undefined. (line 31, file "Code"), which together with testing other modifications indicates to me that kept is empty. What am I missing?

tabulator update column data

I've a table set up with Tabulator with unknown data ( pulled from a file) so i can't make a column definitions setup for it except for general setup that works with any kind of data.
now I'm in situation that i need to add certain code for each row under column code which is included with the existing table.
i looked for away to add code something like SX0001 on the first row and just add 1 each row so the second row would be look like SX0002
I've checked this link http://tabulator.info/docs/4.1/update#alter-replace i saw some functions that works on rows but not columns .
solution i'm trying to achieve:-
the link includes under updateData function that i need to have index with default value (Id)
giving that I'm not sure what type of date it might have or be included with the table i've added a new column using this code
table.addColumn({title:"id", field: "id" , formatter:"rownum",width:40, align:"center"} , true)
now I don't know how to get the Length of the Column to loop through each one of the column and run function like this
var no = 1000;
var str = "SX";
var x = str + no ;
table.updateData([{id:1, code:x}]);
var no = no +1;
is there's anyway to do this ?
You can retrieve the data stored in the table using the getData function.
var data = table.getData();
This will return an array containing the data objects for each row in the table.
Then to get your lenght just do data.length
If you want to count the table data the getDataCount exactly for this, which returns a count of rows in the table:
var count = table.getDataCount();
But actually your current approach will result in the table being redrawn a load of times as you update the row data.
Mutators
Instead you should look at using a Mutator, these allow you to alter data as it enters the table, so in this case you could do something like this:
//global variable to keep track of row id
var rowCount = 0;
//custom mutator
var idMutator = function(value, data, type, params, component){
//increment rowCount and assign as column value
return rowCount++;
}
//in your column definition set this mutator
{title:"ID", field:"id", mutatorData:idMutator}
By using this approach the value is set as the data is loaded into the table, nothing needs to be redrawn and the whole proceess is much more efficient

Error: Cannot read property 'replaceChild' of undefined

I am trying to update a table to display the new row when I save a record. My code currently loads the entire table again along with the existing table. For example, I'm seeing rows 1-15, then I add a row and see 31 total rows, rows 1-15 and then rows 1-16 all in the same table.
Here is my code for the replace function which calls my original load function when it's time to replace the data. I based this off another example I saw.
function replaceData() {
var old_tbody = document.getElementsByTagName('tbody');
var new_tbody = document.createElement('tbody');
loadData(new_tbody);
old_tbody.parentNode.replaceChild(new_tbody,old_tbody);
console.log("Data replaced");
}
I'm clearly not a JavaScript expert so any help would be appreciated.
getElementsByTagName function returns a HTML Collection (array-like object), that means that you have to specify which item of that array you want (even if there is only one item).
So your code basically should be:
var old_tbody = document.getElementsByTagName('tbody')[0];
Or you can use querySelector which returns only the first matched element. Like this:
var old_tbody = document.querySelector('tbody');
getElementsByTagName actually returns a collection of elements, so parentNode
doesn't work. To get the actual DOM node you would do the following.
var old_tbody = document.getElementsByTagName('tbody')[0];

Javascript array grid object property serialized by Kendo is null on server

I have a Kendo grid that I have an editable detail template. In the detail template, I have a multiselect.
When I save, I am manually updating the dataItem to grab the most up to date options in the detail template's multiselect. There is no problem with grabbing the data from the multiselect. Everything actually looks pretty good until I trigger the grid to save.
I add the multiselect items to the grid's dataItem with this code:
function SaveRefItemSubCategories() { //Called on Save button click
var grid = $("#RefItemSubCategoryGrid").data("kendoGrid");
for (var i = 0; i < grid.dataSource._data.length; i++) {
var dataItem = grid.dataSource._data[i];
dataItem.RefItemCategoryServiceIDs = [];
var ms = $("#MultiSelect_" + dataItem.uid).data("kendoMultiSelect");
var values = ms.value();
for(var x = 0; x < values.length; x++) {
dataItem.RefItemCategoryServiceIDs.push(values[i]);
}
}
grid.dataSource.sync();
}
At that point, when I look at what is posted to the server, the grid's dataSource looks like this for the serialized multiselect items:
models[0].RefItemCategoryServiceIDs[] 15
&models%5B0%5D.RefItemCategoryServiceIDs%5B%5D=15
It should look like this:
models[0].RefItemCategoryServiceIDs[0] 15
&models%5B0%5D.RefItemCategoryServiceIDs%5B 0%5D=15
Sorry for extra space in there, I couldn't get it to bold otherwise
The lack of the array's index in the serialized data results in that property being null when it hits the server. this property's type is List
I have tried a couple different approaches, but the end up creating new properties on the dataItem that stick around and cause problems after I save for the first time.
Some examples I've used instead of the push() method are:
This one does send the data back, but it ignores the existing list and creates a new dataSource property for each array index. This would work if I was only saving once, but if I save the grid multiple times, then the properties added stick around and mess with data integrity. I would entertain this option if a way to 'reset' the dataSource was possible after saving (without reloading the grid).
dataItem["RefItemCategoryServiceIDs[" + i + "]"] = values[i];
This one had the same effect as the .push(), which is the property on my object on the server being null
dataItem.RefItemCategoryServiceIDs[i] = values[i];
Please let me know if I can provide any more information and thanks in advance!
I'm not confident that this is the best way to handle it, but I have puzzled out a way that works.
I changed adding to the data item's properties from this:
for(var x = 0; x < values.length; x++) { //values is array from multiselect
dataItem.RefItemCategoryServiceIDs.push(values[i]);
}
to this:
for (var i = 0; i < values.length; i++) { //values is array from multiselect
dataItem["RefItemCategoryServiceIDs[" + i + "]"] = values[i];
}
Just this change works for every scenario EXCEPT this:
Save row with 2 options chosen from multiselect, resulting in 2 properties being added to the dataItem. We'll say the ID's of those items are 1 and 21. Posted data looks like this:
models[0].RefItemCategoryServiceIDs[0] = 1
models[0].RefItemCategoryServiceIDs[1] = 21
After saving, if we open that multiselect again and delete the first option (the one with ID 1), we get the following data posted:
models[0].RefItemCategoryServiceIDs[0] = 21
models[0].RefItemCategoryServiceIDs[1] = 21
Which is obviously not right (should just be 1 entry with the ID set to 21). This is happening because the RefItemCategoryServiceIDs isn't really an array, just properties whose names look like array entries so that they serialize into a list on the server (as I understand it). To mitigate this issue, I preceded the code that maps the current multiselect values to delete the existing properties associate with this array:
function CleanDataItemLists(dataItem) {
if (dataItem.RefItemCategoryCarrierIDs != undefined && dataItem.RefItemCategoryCarrierIDs.length > 0) {
var i = 0;
//Continues to remove properties by index until none are left
while (dataItem.RefItemCategoryCarrierIDs[i] != undefined) {
delete dataItem["RefItemCategoryCarrierIDs[" + i + "]"];
i++;
}
//Cleans up empty array property
delete dataItem.RefItemCategoryCarrierIDs;
}
return dataItem;
}
After this function is called, you can execute the for loop code referenced above and the data serializes with an index present (See initial post for example of missing index in serialized data), allowing the server to map it to the list object. Like I said, I'm not convinced that this is the best way to do this, but it does work for me. Hopefully, this can help someone else or lead to an even better answer.

indexOf returning -1 despite object being in the array - Javascript in Google Spreadsheet Scripts

I am writing a script for a Google Docs Spreadsheet to read a list of directors and add them to an array if they do not already appear within it.
However, I cannot seem to get indexOf to return anything other than -1 for elements that are contained within the array.
Can anyone tell me what I am doing wrong? Or point me to an easier way of doing this?
This is my script:
function readRows() {
var column = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("Director");
var values = column.getValues();
var numRows = column.getNumRows();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var directors = new Array();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (directors.indexOf(row) == -1) {
directors.push(row);
} else {
directors.splice(directors.indexOf(row), 1, row);
}
}
for (var i = 2; i < directors.length; i++) {
var cell = sheet.getRange("F" + [i]);
cell.setValue(directors[i]);
}
};
When you retrieve values in Google Apps Script with getValues(), you will always be dealing with a 2D Javascript array (indexed by row then column), even if the range in question is one column wide. So in your particular case, and extending +RobG's example, your values array will actually look something like this:
[['fred'], ['sam'], ['sam'], ['fred']]
So you would need to change
var row = values[i];
to
var row = values[i][0];
As an aside, it might be worth noting that you can use a spreadsheet function native to Sheets to achieve this (typed directly into a spreadsheet cell):
=UNIQUE(Director)
This will update dynamically as the contents of the range named Director changes. That being said, there may well be a good reason that you wanted to use Google Apps Script for this.
It sounds like an issue with GAS and not the JS. I have always had trouble with getValues(). Even though the documentation says that it is a two dimensional array, you can't compare with it like you would expect to. Although if you use an indexing statement like values[0][1] you will get a basic data type. The solution (I hope there is a better way) is to force that object into a String() and then split() it back into an array that you can use.
Here is the code that I would use:
var column = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("Director");
var values = column.getValues();
values = String(values).split(",");
var myIndex = values.indexOf(myDirector);
If myDirector is in values you will get a number != -1. However, commas in your data will cause problems. And this will only work with 1D arrays.
In your case: var row = values[i]; row is an object and not the string that you want to compare. Convert all of your values to an array like I have above and your comparison operators should work. (try printing row to the console to see what it says: Logger.log(row))
I ran into a similar problem with a spreadsheet function that took a range as an object. In my case, I was wanting to do a simple search for a fixed set of values (in another array).
The problem is, your "column" variable doesn't contain a column -- it contains a 2D array. Therefore, each value is it's own row (itself an array).
I know I could accomplish the following example using the existing function in the spreadsheet, but this is a decent demo of dealing with the 2D array to search for a value:
function flatten(range) {
var results = [];
var row, column;
for(row = 0; row < range.length; row++) {
for(column = 0; column < range[row].length; column++) {
results.push(range[row][column]);
}
}
return results;
}
function getIndex(range, value) {
return flatten(range).indexOf(value);
}
So, since I wanted to simply search the entire range for the existance of a value, I just flattened it into a single array. If you really are dealing with 2D ranges, then this type of flattening and grabbing the index may not be very useful. In my case, I was looking through a column to find the intersection of two sets.
Because we are working with a 2D array, 2dArray.indexOf("Search Term") must have a whole 1D array as the search term. If we want to search for a single cell value within that array, we must specify which row we want to look in.
This means we use 2dArray[0].indexOf("Search Term") if our search term is not an array. Doing this specifies that we want to look in the first "row" in the array.
If we were looking at a 3x3 cell range and we wanted to search the third row we would use 2dArray[2].indexOf("Search Term")
The script below gets the current row in the spreadsheet and turns it into an array. It then uses the indexOf() method to search that row for "Search Term"
//This function puts the specified row into an array.
//var getRowAsArray = function(theRow)
function getRowAsArray()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the current spreadsheet
var theSheet = ss.getActiveSheet(); // Get the current working sheet
var theRow = getCurrentRow(); // Get the row to be exported
var theLastColumn = theSheet.getLastColumn(); //Find the last column in the sheet.
var dataRange = theSheet.getRange(theRow, 1, 1, theLastColumn); //Select the range
var data = dataRange.getValues(); //Put the whole range into an array
Logger.log(data); //Put the data into the log for checking
Logger.log(data[0].indexOf("Search Term")); //2D array so it's necessary to specify which 1D array you want to search in.
//We are only working with one row so we specify the first array value,
//which contains all the data from our row
}
If someone comes across this post you may want to consider using the library below. It looks like it will work for me. I was getting '-1' return even when trying the examples provide (thanks for the suggestions!).
After adding the Array Lib (version 13), and using the find() function, I got the correct row!
This is the project key I used: MOHgh9lncF2UxY-NXF58v3eVJ5jnXUK_T
And the references:
https://sites.google.com/site/scriptsexamples/custom-methods/2d-arrays-library#TOC-Using
https://script.google.com/macros/library/d/MOHgh9lncF2UxY-NXF58v3eVJ5jnXUK_T/13
Hopefully this will help someone else also.
I had a similar issue. getValues() seems to be the issue. All other methods were giving me an indexOf = -1
I used the split method, and performed the indexOf on the new array created. It works!
var col_index = 1;
var indents_column = main_db.getRange(1,col_index,main_db.getLastRow(),1).getValues();
var values = String(indents_column).split(","); // flattening the getValues() result
var indent_row_in_main_db = values.indexOf(indent_to_edit) + 1; // this worked
I ran into the same thing when I was using
let foo = Sheet.getRange(firstRow, dataCol, maxRow).getValues();
as I was expecting foo to be a one dimensional array. On research for the cause of the apparently weird behavior of GAS I found this question and the explanation for the always two dimensional result. But I came up with a more simple solution to that, which works fine for me:
let foo = Sheet.getRange(firstRow, dataCol, maxRow).getValues().flat();

Categories

Resources