Sorting a Google SpreadSheet or Google Doc table by column - sorting

I've made a script that takes data from a spreadsheet , creates a Google Doc and presents selected rows in a Table format in the Doc. Now I'd like to be able to sort that table Alphabetically before the table is created. I've tried using a couple of different approaches like this
function onEdit(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var editedCell = sh.getActiveRange().getColumnIndex();
if(editedCell == 2) {
var range = sh.getRange("A2:B10");
range.sort({column: 2});
}
}
This kind of sort works but only onEdit(). I'd like to sort before edit or find away to sort the table as the Google Doc is being generated.
Does anyone have any suggestions.
Many thanks in advance.

Use the onOpen() function instead of the onEdit() function.
Note that you will have to open the document, not just refresh the page to get the function to run.

Related

Text-Widget Applied to an aggregated data table

Utilizing the solution provided by Gordon, I've successfully created a selectable table that contains aggregated data. Now I would like to filter the data with the text-filter-widget.
I understand that the filter needs an array to work properly. What I am trying to understand is how might one be able to update the table rows when the table filters are looking at a group?
A text filter widget is different from a chart in that it takes a dimension to filter on.
We also need to declare a second market dimension so that it will filter the table.
Thus
var marketDim, marketDim2;
// ...
marketDim = facts.dimension(function(d) {
return d.Location;
});
marketDim2 = facts.dimension(function(d) {
return d.Location;
});
// ...
search
.dimension(marketDim2);
Fork of your fiddle.

Google sheets script Exceeded maximum execution time

I wrote a script to import stock data from a csv file stored in Google Drive to an existing google sheet.
In one function I'm doing this for multiple csv files. Unfortunately I get "Exceeded maximum execution time" sometimes, but not all the time.
Do you have an idea how I can boost performance on this:
//++++++++++++++ SPY +++++++++++++++++++
var file = DriveApp.getFilesByName("SPY.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
//Create new temporary sheet
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var yourNewSheet = activeSpreadsheet.getSheetByName("SPY-Import");
if (yourNewSheet != null) {
activeSpreadsheet.deleteSheet(yourNewSheet);
}
yourNewSheet = activeSpreadsheet.insertSheet();
yourNewSheet.setName("SPY-Import");
//Import
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
//Copy from temporary sheet to destination
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A:B').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('SPY'), true);
spreadsheet.getRange('A2').activate();
spreadsheet.getRange('\'SPY-Import\'!A:B').copyTo(spreadsheet.getActiveRange(),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
//Delete temporary sheet
// Get Spreadsheet Object
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// Get target sheet object
var sheet = spreadsheet.getSheetByName("SPY-Import");
// Delete
spreadsheet.deleteSheet(sheet);
Thanks in advance!
I believe your situation and goal as follows.
You have several CSV files like SPY.csv.
Your Spreadsheet has the several sheet corresponding to each CSV file like SPY.
You want to put the values from the CSV data to the Spreadsheet.
You want to put the values of the column "A" and "B" of the CSV data.
In your current situation, you copied the script in your question several times and run them by changing the csv filename and sheet name.
You want to reduce the process cost of your script. I understood your goal like this.
Modification points:
SpreadsheetApp.getActiveSpreadsheet() is used several times. And, activate() is used several times.
I think that in your case, SpreadsheetApp.getActiveSpreadsheet() can be declared one time, and activate() is not required to be used.
In order to copy the CSV data to Spreadsheet, the CSV data is put to a temporal sheet and the required values are copied to the destination sheet.
In this case, I think that the CSV data is directly put to the destination sheet by processing on the array.
I think that above points lead to the reduction of process cost. When above points are reflected to your script, it becomes as follows.
Modified script:
Please copy and paste the following script and prepare the variable of obj. When you run the script, the CSV data is retrieved and processed, and then, the values are put to the Spreadsheet.
function myFunction() {
var obj = [
{filename: "SPY.csv", sheetname: "SPY"},
{filename: "###.csv", sheetname: "###"},
,
,
,
];
var ss = SpreadsheetApp.getActiveSpreadsheet();
obj.forEach(({filename, sheetname}) => {
var file = DriveApp.getFilesByName(filename);
if (file.hasNext()) {
var sheet = ss.getSheetByName(sheetname);
if (sheet) {
// sheet.clearContents(); // Is this requierd in your situation?
var csv = DriveApp.getFileById(file.next().getId()).getBlob().getDataAsString();
var values = Utilities.parseCsv(csv).map(([a, b]) => [a, b]);
sheet.getRange(2, 1, values.length, 2).setValues(values);
}
}
});
}
Note:
Please use this script with enabling V8
I'm not sure about your CSV data. So when Utilities.parseCsv(csv) cannot be used, please use the delimiter.
In this modification, Spreadsheet service is used. If above modified script occurs the same error of Exceeded maximum execution time, please tell me. At that time, I would like to propose the sample script using Sheets API.
References:
Spreadsheet Service
parseCsv(csv)

onEdit(e) trigger doesn't work for me - Google Sheets, Google Apps Script

I just tried to sort a column with names alphabetically once a new name is added or an existing name is edited (I started the sorting process from row two because row one is my header). I used the onEdit(e) trigger as shown. It should be a simple thing to do but it does not work. When I add a name to the sheet or edit an existing one nothing happens.
ss = SpreadsheetApp.openById("1nQZT16wiN9AX6FqZhioKyeLWoL7_BKfi09zRg");
sheet = ss.getSheetByName("Sheet1");
function onEdit(e) {
range = sheet.getRange(2, 1, sheet.getLastRow()-1);
range.sort(1);
}
The Spreadsheet looks like as seen in the picture:
I hope that someone has a solution to that problem.
You're getting spreadsheet in global scope:
ss = SpreadsheetApp.openById("1nQZT16wiN9AX6FqZhioKyeLWoL7_BKfi09zRg");
This requires any of the following scopes:
https://www.googleapis.com/auth/spreadsheets.currentonly
https://www.googleapis.com/auth/spreadsheets
But simple triggers run without authorization1. Therefore, You cannot use SpreadsheetApp.openById(). You could however get the spreadsheet from the event object2 inside the onEdit:
const onEdit = e => e.source
.getSheetByName("Sheet1")
.getRange("A2:A")
.sort(1)
If you want to open any other spreadsheet than the current bound one, you'd need to use installable triggers

How to iterate through a hidden column in jquery data table

I have a data table that has a hidden column. I want to set the values of that column to a java script array. (Note: I want to get the values that belong to the current page only). If I use a search filter, I want the values of the current page of the search result.
I've tried like this.
$('#datatbl').DataTable().rows({filter: 'applied'}).every(function () {
var row = this.data();
arr.push(row[0]);
});
But,this code gives all values from all the pages. Please help....
Try adding page:'current' in selector.
$('#datatbl').DataTable().rows({filter: 'applied', page:'current'})

idPrefix usage in jqGrid

Given a jqGrid populated with local data and created with the option of idPrefix:"custTable" , all the generated rows get the prefix in the html id i.e. custTableRow_1 custTableRow_2 etc. Does this idPrefix'ed version of the id need to be passed in to the jqGrid methods, if so which ones?
for example to delete a row with deleteRowData does it need the prefixed id? how about setRowData or addRowData? when adding after row x it seems to need the prefixed for the srcrowid parameter. How about multiselect rows?
If I delete a row using the prefixed id of the row it disappears from the display but when I reload the grid the delete item shows up again in the grid, like it wasn't removed. This doesn't happen when idPrefix is not used.
thanks for any help.
The option idPrefix was introduced to hold ids on the HTML page unique even you have on the page the ids like the rowids loaded from the server. Typical example is two grids with the data loaded from the server. Let us you have two tables in the database where you use IDENTITY or AUTOINCREMENT in the definition of the PRIMARY KEY. In the case the primary key will be generated automatically in the table and will be unique inside the table, but there are not unique over the tables. So if you would use the primary keys as ids of the grids and place on one page two grids you can have id duplicates.
To solve the problem you can use idPrefix: "a" as additional option in the first grid and use idPrefix: "b" in the second grid. In the case locally jqGrid will uses everywhere ids with the prefix, but the prefix will be cut if the ids will be sent to the server.
So you will see locally in all callbacks (events) and in all methods (like setRowData, addRowData etc) the ids with the prefix, but on the server side the ids the prefixes will be removed immediately before sending to the server.
I recommend you additionally to read another answer about the restrictions in the ids which I posted today.
UPDATED: I looked through the code which you posed on jsfiddle and found some clear bugs in your code. You current code
1) use wrong algorithm to generate id of the new row. For example the following code
// generic way to create an animal
function newAnimal(collection, defaults) {
var next = collection.length + 1;
var newpet = {
id : next,
name: defaults.name + next,
breed: defaults.breed
};
return newpet;
}
use collection.length + 1 for the new id. It's wrong if you allows to delete the items. By adding of two items, deleting one from there and adding new item one more time follows to id duplicates. Instead of that it's more safe to use some variable which will be only incremented. You can use $.jgrid.randId() for example which code is very simple.
2) you call addRowData with adding a prefix manually (see dogsPrefix+newdog.id below). It's wrong because jqGrid adds the prefix one more time to the rows.
// add dog button actions
$('#dogAddAtEnd').click(function() {
var newdog = newAnimal(dogs, dogDefaults);
dogs.push(newdog);
dogAdded();
dogsTable.jqGrid('addRowData', dogsPrefix+newdog.id, newdog);
});
Probably there are more problems, but at least these problems can explain the problems which you described.
UPDATED 2: I examined new demo which you posted. It has still the lines
grid.jqGrid('addRowData', newanimal.id, newanimal,
"after", prefix+ followingId);
and
dogsTable.jqGrid('addRowData', dogsPrefix+newdog.id, newdog);
which must be fixed to
grid.jqGrid('addRowData', newanimal.id, newanimal,
"after", followingId);
and
dogsTable.jqGrid('addRowData', newdog.id, newdog);
Nevertheless I tested the demo after the changes and found bugs in code of addRowData, delRowData and setRowData. The problem are in the line of the delRowData and the same line of setRowData
var pos = $t.p._index[rowid];
can be fixed to the following
var id = $.jgrid.stripPref($t.p.idPrefix, rowid), pos = $t.p._index[id];
Inside of addRowData I suggest to include the line
var id = rowid; // pure id without prefix
before the line
rowid = t.p.idPrefix + rowid;
of addRowData. Another tow lines of addRowData
lcdata[t.p.localReader.id] = rowid;
t.p._index[rowid] = t.p.data.length;
should be changed to
lcdata[t.p.localReader.id] = id;
t.p._index[id] = t.p.data.length;
where unprefixed id will be used.
The modified code of you demo which uses the fixed version of jquery.jqGrid.src.js you can test here.
I will post my bug report to trirand later to inform the developer of the jqGrid. I hope that soon the bug fix will be included in the main code of jqGrid.
Additionally I recommend you to use $.jgrid.stripPref method to strip prefixes from the rowids. For example the function
//general delete selected
function deleteSelectedAnimal(list, grid, prefix)
{
var sel = grid.jqGrid('getGridParam', 'selrow');
if (sel.length)
{
var gridrow = sel;
//get the unprefixed model id
var modelid = gridrow;
if (prefix.length !== 0)
{
modelid = modelid.split(prefix)[1];
}
// make it a numeric
modelid = Number(modelid);
//delete the row in the collection
list = RemoveAnimal(list, modelid);
//delete the row in the grid
grid.jqGrid('delRowData', gridrow);
}
}
from your demo can be rewritten to the following
//general delete selected
function deleteSelectedAnimal(list, grid)
{
var sel = grid.jqGrid('getGridParam', 'selrow'),
gridPrefix = grid.jqGrid('getGridParam', 'idPrefix');
if (sel !== null)
{
//delete the row in the collection
// ??? the gogs list will be not modified in the way !!!
list = RemoveAnimal(list, $.jgrid.stripPref(gridPrefix, sel));
//delete the row in the grid
grid.jqGrid('delRowData', sel);
}
}
I am not sure that the line list = RemoveAnimal(list, $.jgrid.stripPref(gridPrefix, sel)); or the function RemoveAnimal do what you want, but it's not a problem which connected with jqGrid.
One more small remark about your code. You use already in the objects which you add to the grid the id property. It's the same name as defined in the localReader.id. In the case the data from the id property will be used as id attribute of the grid rows (<tr>). The local data parameter will save the id additionally to other properties which are build from the name property of the items of colModel. So I see no sense to define hidden column
{ key: true, name: 'id', align: 'left', hidden: true }
How you can see on the demo all stay works exactly as before if you remove id column from the grids which you use.
UPDATED 3: As promised before I posted the corresponding bug report here.

Resources