I want to get all the rows of JQGrid in a javascript variable in a certain order.
I was able to get the data of all rows by :
var rowData = $("#gridId").jqGrid("getRowData");
But I want the rows to appear in the same order as that I entered in the grid.
I am trying to create a table and get its column details through the grid. So I require the order of the columns to remain the same. Any suggestions?
You can explicitly push the jqgrid rowdata to an array and then convert that to json string.
To do that you may use a function like the one given below to iterate through the jqgrid rows:(From Oleg's answer)
var gridData= {};
var $grid = jQuery("#gridId"), rows = $grid[0].rows, cRows = rows.length,
iRow, rowId, row, cellsOfRow;
for (iRow = 0; iRow < cRows; iRow++) {
row = rows[iRow];
if ($(row).hasClass("jqgrow")) {
cellsOfRow = row.cells;
// row represent the row with cellsOfRow.length cells.
// So one can use for loop with iCol between 0 and cellsOfRow.length
// cellsOfRow[iCol] represent the cell with the index iCol
// and $(cellsOfRow[iCol]).text() - the text of the cell
}
}
Inside the loop you can push the celldata to an array.
gridData['column_index1'] = $(cellsOfRow[0]).text();
gridData['column_index2'] = $(cellsOfRow[1]).text();
.............................................
Finally convert gridData to json string using
var result = JSON.stringify(gridData) ;
Related
I am new to google apps script and I was trying to get all the values in a particular column inside a sheet named "Items". I was able to create a loop to get to the last row that contains value but when I try to use the function, no data is retrieved. I tried console.log(values[lr][0]); inside the if clause and it outputs just fine.
Here's my code
function getAllItems()
{
var ss= SpreadsheetApp.getActiveSpreadsheet();
var locationSheet = ss.getSheetByName("Items");
var values = locationSheet.getRange("Items!B2:B").getValues();
for(var i = values.length - 1 ; i >= 0 ; i--){
if (values[i][0] != null && values[i][0] != ""){
lr = i + 1;
values.sort();
return values[lr][0];
}
}
}
There are several ways to retrieve values from a column in Google Sheets.
The basics, getting the sheet
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('Items');
SpreadsheetApp.getActiveSpreadsheet() works in bounded projects and add-ons. Spreadsheet.getSheetByName(name) works when the sheet name is known.
Getting the column values by using Sheet.getRange and an open reference using A1 notation
var values = sheet.getRange('B:B').getValues();
If your spreadsheet has blank rows at the bottom, in this case Range.getValues besides the column values, it will return an empty string for each blank rows.
Besides using Sheet.getRange with an open reference, it might be used with other reference types and using start row, start column, number of rows and number of columns.
Getting the column values by using Sheet.getRange and an open reference using A1 notation excluding empty strings
var values = sheet.getRange('B:B').getValues().filter(String);
Getting the column values by using Sheet.getDataRange and Array.prototype.map
var values = sheet.getDataRange().getValues().map(row => row[1]);
Only will return the values from the first row to the last row of the data range. The data range is determined from A1 to the last row and last column having values, i.e., if one column B have values from row 1 to row 10 and column C have values from row 4 to row 20, the data range reference is A1:C20, so values will contain the values from row 1 to row 20, showing empty strings for the blank cells.
Getting the column values by using Sheet.getDataRange, Array.prototype.splice and Array.prototype.getLastIndex
var values = sheet.getDataRange().getValues();
values.splice(values.findLastIndex(String) + 1);
Only will return the values from the first row to the last row of the column containing non empty strings. This might be helpful when having columns "of different sizes", as explained in the previous case. Please note that if there blank cells in between, an empty string will be included as value of these cells.
Notes:
Instead of Range.getValues you might use Range.getDisplayValues to get the strings with the values formatted as strings as they are displayed on Google Sheets cells. Both methods return the values structured as an Array of Arrays, this might be handy if you will be adding the values to another range, but if you want to add them to the execution logs you might want to format them in another way.
Please bear in mind that if the column content is very large, nowadays a Google Sheets spreadsheet could have up to 10 million cells and each cell could have upto 50k characters, the column content will be truncated when printed to the execution logs.
Related
Get column from a two dimensional array
Resources
Array
You don't need a loop for that (explanation in comments):
function getAllItems()
{
var ss= SpreadsheetApp.getActiveSpreadsheet();
var locationSheet = ss.getSheetByName("Items");
var values = locationSheet.getRange("Items!B2:B").getValues().flat(); // 2D -> 1D array
var filter_values = values.filter(r=>r!=''); // remove empty rows
Logger.log(filter_values); // get the full list
Logger.log(filter_values[filter_values.length-1]); // get the last value;
return filter_values[filter_values.length-1];
}
Try this:
function getAllItems(){
var ss= SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Items");
var vs = sh.getRange("B2:B"+sh.getLastRow()).getValues();//all the values in column B
return sh.getLastRow();//the last row with data
}
Or you can use:
function getColumnHeight(col, sh, ss) {
var ss = ss || SpreadsheetApp.getActive();
var sh = sh || ss.getActiveSheet();
var col = col || sh.getActiveCell().getColumn();
var rcA = [];
if (sh.getLastRow()){ rcA = sh.getRange(1, col, sh.getLastRow(), 1).getValues().flat().reverse(); }
let s = 0;
for (let i = 0; i < rcA.length; i++) {
if (rcA[i].toString().length == 0) {
s++;
} else {
break;
}
}
return rcA.length - s;
//const h = Utilities.formatString('col: %s len: %s', col, rcA.length - s);
//Logger.log(h);
//SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(h).setWidth(150).setHeight(100), 'Col Length')
}
function getAllItems(){
var ss= SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Items");
var vs = sh.getRange("B2:B"+getColumnHeight(2,sh,ss).getValues();//all the values in column B
return sh.getLastRow();//the last row with data
}
If you use filter() to filter out all of the nulls you may not get the desired result if one of the data elements is null.
I need to get values and row number in Google sheet script out of sellected range.
Original problem was that I was trying to get values and row numbers of sellected range using this script:
sheet = ss.getActiveSheet(),
sheetvalues = sheet.getActiveRange().getValues();
for (i=0; i<sheetvalues.length; i++) {
mr = sheet.getActiveRange().getRow()+i;
}
But I found out that if you use filer and select a range then all the hidden cells will also be part of the activerange, but I need only those that are inside of a filtered range. I decided that the best way is to select cells separately one by one.By I can't get a value and row index cause it counts as active range only the last selected cell.
I believe your goal as follows.
Under the selected rows for the sheet, you want to retrieve the row numbers of no selected rows using Google Apps Script.
In this case, I think that the method of getSelection can be used. And, in order to confirm the rows, getActiveRangeList is used. When this is reflected to a sample script, it becomes as follows.
Sample script:
When you use this script, at first, please select the cells like your sample image and run the script.
function myFunction() {
// 1. Retrieve the selected ranges.
const selection = SpreadsheetApp.getSelection();
// 2. Retrieve the selected row numbers.
const selectedRows = selection.getActiveRangeList().getRanges().flatMap(r => {
const row = r.getRow();
const temp = [];
for (let i = 0; i < r.getNumRows(); i++) {
temp.push(row + i);
}
return temp;
}).sort((a, b) => a - b);
// 3. From data range, retrieve the row numbers except for the selected row numbers.
const sheet = selection.getActiveSheet();
const range = sheet.getDataRange();
const rowNumbers = [];
for (let r = 1; r <= range.getNumRows(); r++) {
if (!selectedRows.includes(r)) rowNumbers.push(r);
}
console.log(rowNumbers); // Here, you can see the retrieved row numbers at the log.
// 4. Retrieve the row values of the retrieved row numbers.
// If you want to retrieve the row values of "rowNumbers", you can also the following script.
const allValues = range.getValues();
const values = rowNumbers.map(n => allValues[n]);
console.log(values); // Here, you can see the values of row numbers at the log.
}
As the important point for using the selected range, for example, when the cells of row 3, row 1, row 2 are selected in order, the range list returns the order of cells. So in this sample script, the retrieved row numbers are sorted.
When above script is run, for example, when the data range is "A1:C5" and when the cells "A1", "A3" and "A5" are selected, the row numbers of 2, 4 are retrieved.
References:
getSelection()
getActiveRangeList()
How to pull data in a range of cell and then push those values into an array of data?
In this code I tried to get those values in range E2:E97 and then push those values to an array such as [E2 value, E3 Value, etc] then set value to database sheet using dataS.getRange(dataS.getLastRow()+1).setValue(value);
but it seems I can't get it done with those code. so any idea to do this?
// Save Data
function saveData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("newform");
var dataS = ss.getSheetByName("newdb");
var dataBaseNameColIndex = 1;
var formDataRange = ['E2:E97'];
var ui = SpreadsheetApp.getUi();
var response = ui.alert(
'Save Data ?',
ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
for (var i = 2; i < formDataRange.length; i++) {
var value = formS.getRange(formDataRange[i], 5).getValue();
dataS.getRange(dataS.getLastRow() + 1).setValue(value);
console.log(saveData);
}
}
}
Instead of trying to copy and paste data cell-by-cell, you may want to do it in one go. That would be more efficient.
So instead of:
var value = formS.getRange(formDataRange[i], 5).getValue();
you could use the following without the for loop:
var allValues = formS.getRange('E2:E97').getValues();
And then post the data to the new range like this:
dataS.getRange(dataS.getLastRow() + 1, 2, allValues.length, allValues[0].length).setValues(value);
I am assuming you want to paste the data into column 2 onwards. Adjust the 2nd value in getRange() above accordingly.
The 3rd and 4th values in getRange() above are the number of rows and columns to pasts.
allValues.length is the number of rows of data. In this case it would be 95.
and allValues[0].length would the number of columns in the top row of the data copied. And in this case it should be one.
I am suggesting this way as you won't need to keep fiddling with the number of rows and columns if you change the copy range dimensions later on.
PS:
dataS.getRange(dataS.getLastRow() + 1).setValue(value);
is missing the column number in getRange()
I am using jQuery to inject values from an JSON object into an existing, empty table.
What I want to do is fill up my table top-to-bottom, instead of what it does now - left to right. So how would I modify this snippet to accomplish what I want?
_.each(dataset, function(v, k){
$("tr td:empty:first", "#myTable tbody").html("<strong>"+v+"</strong>");
});
I guess that It would be possible to target the td in the column which has the fewest filled rows, but how?
Change your selector to:
$("tr td:empty:first:first-child", "#myTable tbody")
So that it matches only when the table cell is the first-child of it's parent, the row, so will only insert in the first column.
Edit: A method to populate the table based on a known and limited number of columns
It works by selecting each table column using the nth-child of each row, then concatenating the columns together, and filtering for the first empty one.
var cells = [].concat(
$('tr td:nth-child(1)').get(),
$('tr td:nth-child(2)').get(),
$('tr td:nth-child(3)').get(),
$('tr td:nth-child(4)').get()
)
_.each(dataset, function(v, k){
$(cells).filter(':empty:first').html("<strong>"+v+"</strong>");
});
Edit: Generic version
// create array to hold cells ordered by column
var cells = [];
// loop through desired columns adding to cells array
// hint: you can specify column `from` and `to` in the for loop definition
for(i=1;i<=4;i++)
cells = cells.concat($('tr td:nth-child('+i+')').get());
// loop through the data, populating each column in order
_.each(dataset, function(v, k){
$(cells).filter(':empty:first').html("<strong>"+v+"</strong>");
});
Is dataset an array? If so, something like this:
var self;
$('#myTable tr:has("td:empty")', function (index, elem) {
if (index < dataset.length) {
self = $(this);
self.find('td:empty').html("<strong>"+dataset[i]+"</strong>")
}
});
..fredrik
Here's what I ended up doing, using underscore.js to iterate the dataset:
var currentCol = 0;
var currentRow = 0;
var renderedCount = 0;
_.each(dataset, function(v, k) {
/* Switch to a new column when we have rendered enough (4)
* elements vertically per column and reset the rowcounter.
*/
if (renderedCount % 4 === 0) {
currentCol++;
currentRow = 0;
}
// Inject our value as HTML into the first empty TD per column
$("tr:eq("+currentRow+") td:empty:first", "#mytable tbody").html(v);
// Increment current row count and our renderedCount
currentRow++;
renderedCount++;
});
Many thanks to #BillyMoon for helping out!
Update:
To create the empty table before doing the above, I did this:
// To allow repeating strings (n) times. Borrowed from someone on SO
String.prototype.repeat = function( num ) {
return new Array( num + 1 ).join( this );
}
// Setup our wanted maximum amount of columns horizontally and our table structure
var maxColsPerRow = 4;
var rowHTML = "<tr>"+'<td></td>'.repeat(maxColsPerRow)+"</tr>";
var datasetCount = _.keys(dataset).length; // Amount of properties in our dataset calculated with underscore.js keys()-method.
// Append as many empty rows&cells to our table that we'll need
$("#myTable tbody").html( rowHTML.repeat( Math.round( datasetCount/maxColsPerRow));
I'm looking for some ideas of how to accomplish this as I am hitting a wall on it.
I have a table that displays data pulled from a MySQL db. The table goes in a sequence of a row of 13 cells with displayed data followed by a hidden row of one cell. The hidden row is toggled by clicking a link in cell index 1 of the previous row. Like so:
row 1 : click this cell to show row 2 : another cell : another cell : ad nauseum till we get to 13 :
row 2 which is hidden
row 3 : click this cell to show row 2 : another cell : another cell : ad nauseum till we get to 13 :
row 4 which is hidden
...
so using jquery I pulled all the rows, then set a test to determine if it was a displayed row or hidden row, if it was displayed then I put that row and the following one into an object and then placed that object into another object, like so:
//this function is for sorting the data in the table
$(".sort").click(function() {
//get what column we are sorting by
var sortBy = $(this).attr('sortBy');
//set the colnum to sort by
if (sortBy == "itemname") {
var sortCol = 1;
} else if (sortBy == "priority") {
var sortCol = 2;
} else if (sortBy == "livedate") {
var sortCol = 10;
} else if (sortBy == "status") {
var sortCol = 11;
} else if (sortBy == "designer") {
var sortCol = 12;
}
//get the table data
var tableData = getTableData("NO", "null", "YES", sortBy);
//get all the rows
var tableRowArray = $("#productTableBody tr");
//declare new table object
var tableObj = new Object;
var rowPackage = new Object;
//loop through tableRowArray and put rows into packages of two, the main row and the hidden row
for(var t=0; t<tableRowArray.length; t++) {
if($(tableRowArray[t]).children(":first").attr('class') == "colorCode") {
rowPackage[t] = $(tableRowArray[t]).children();
rowPackage[t+1] = $(tableRowArray[t+1]).children();
//dump rows into tableObj
tableObj[t] = rowPackage;
}
//clean out rowPackage
rowPackage = {};
}
var x=-2;
for(thisRow in tableObj) {
x = x+2;
var sortItem = $(tableObj[thisRow][x][sortCol]).html();
//ack! -->getting stumped here
}
});
I've also collected which column the user wants to sort by. I can then find the cell the user wants to sort by. I know I need to pull that info, put into an array and sort but I guess I am getting stumped on how to apply the sorted array back to my tableObj so I can rewrite the table body HTML...the reason I am getting stumped is that some of the data to be sorted will be identical, for example if sorting by designer the data could be this {"a", "b", "c", "c", "a", "a", ""a"}, which when sorted would be a, a, a, a, b, c, c, but since some are identical I can't go back and loop through the object and find the entry that matches the first item in my sorted array, 4 items will match it. So how do I determine which entry in the object matches up with the first a in the sorted list?
Thanks in advance.
That's a tough one, but I suppose there is hardly anything impossible in this life.
I would go like this (using Underscore library)
var packs = [];
// assuming you always have even number of tr's
$("#productTableBody tr:odd").each(function(i, tr){
packs.push( {main: tr, sub: tr.next()} );
// tr.next() will be :even, so it's not yet selected
// now detach rows from the table
// note the order - next() wont work otherwise
tr.next().remove();
tr.remove();
});
var sortedPacks = _(packs).sortBy(function(pack){
return $(pack.main).find('td:nth('+sortCol')').text();
});
// now in sortedPacks you have touples of rows sorted by "main" rows sortCol column
// and you would probably want to restore the table now
$.each(packs, function(i, pack){
$("#productTableBody").append(pack.main).append(pack.sub);
});
The code may not reflect your situation perfectly, but I suppose you should be able to get the main idea.
Not really to easy to get what you are asking for here, but this will at least enable you to get the data sorted.
Start by collecting your data into an array, eg data, each row can be represented by either an array or an object.
Now simply call
data.sort(function(a, b){
// select the two values from a and b depending on the column to sort by
a = a[colNr];
b = b[colNr];
return a == b ? 0 : a < b ? -1 : 1;
});
Now you can easily rebuild your table based on the sorted array.
If you during data-collection also added a reference to the row to the array/object, then you can now remove all rows from the table, loop over the data array, and add each node back to the table.