Inserting an array as a table into a Google doc - google-apps-script

I am creating a document from a Template, and cannot figure out how to insert a table at the right position.
I have the table in memory as a 2D array, and in the template I have place-holders like this (including the square-brackets):
...
[TABLE 1]
...
[TABLE 2]
...
[TABLE 3]
...
Each of these placeholders is in a 1x1 table.
I have managed to insert my first array in the right position, but when I then search for the following placeholders my array always gets inserted after Table 1.
My code is the following (I found this online and adapted it slightly):
function insertTable(targetdoc, stringToReplace, tableValues) {
var body = targetdoc.getBody();
var searchElement = targetdoc.getActiveSection();
var searchType = DocumentApp.ElementType.TABLE;
var searchHeading = DocumentApp.ElementType.TABLE_CELL;
var searchResult = null;
// Search until the table is found.
while (searchResult = searchElement.findElement(searchType, searchResult)) {
var par = searchResult.getElement().asTable();
var tabletext = par.getText();
var substr=tabletext.search(stringToReplace);
if (substr >0 ) {
var childindex = body.getChildIndex(par);
var oTable = body.insertTable(childindex+1, tableValues);
return oTable;
}
}
}
and the calling code is:
var oTable = insertTable(oOutputFile,"["+cFieldID+"]",aTable);
where oOutputfile is the new doc, cFieldID is the placeholder text, and aTable is the 2D array.
Can anyone help me get this to work, so that it inserts each array into the correct position?
Thanks

I have written something very similar that might prove useful to you, see GAS Template Engine
It will accept any JSON string and replace place holders in a document that match the structure of the JSON. When an array is encountered, the script looks for a place holder in a table and it will create table rows for each element of the array.
So if your JSON string contains an array as below :
var json = { myarr : [ { col1: "a", col2 : "b" }, { col1 : "c", col2 : "d" }] }
then the script will look for a table in the template document that looks like this :
------------------------------------------------------
| $myarr.col1 | $myarr.col2 |
-------------------------------------------------------
and transform that into :
-----------------------------------
| a | b |
-----------------------------------
| c | d |
-----------------------------------
it will keep the formatting of the rows as well.
It is just a proof of concept for a templating engine but it should be enough to solve your problem.

Thanks koma for your solution which I will certainly use in future, however it was a bit of overkill for what I was looking for.
Finally, I found the solution to what I needed after a mammoth debugging session, and my function shown above has now become:
function insertTable(targetdoc, stringToReplace, tableValues) {
var oDoc = targetdoc.getBody(); // Document
var oSR = oDoc.findText(stringToReplace); // SearchResult
var oPara = oSR.getElement().asText().getParent(); // Paragraph
var nIndex = oDoc.getChildIndex(oPara); // Index
var oTable = oDoc.insertTable(nIndex, tableValues); // Table
return oTable;
}
so, for example, if I have a doc (oDoc) with the following placeholder
[TABLE 1]
an array
aData: {{"","column 1","column 2"},{"row 1","data 11","data 12"},{"row 2","data 21","data 22"}}
and a variable
cFieldID = "TABLE 1";
and call my function
oTable = insertTable(oDoc, cFieldID, aData);
oOutputFile.replaceText("\\["+cFieldID+"\\]","");
I obtain the following in lieu of the placeholder text
-----------------------------------
| | column 1 | column 2 |
-----------------------------------
| row 1 | data 11 | data 12 |
-----------------------------------
| row 2 | data 21 | data 22 |
-----------------------------------
This is less generic and powerful than koma's solution, but sufficient for what I need for now.
Chris

Related

Checking discord messages with sql

So I've been trying to check each message from a sql table. My sql table structure is down below:
Example:
| id | | triggervalue | | triggermessage |
| 633666515413237791 | | hello, world, test | | Trigger works! |
(array like string is something like: hello, world, test)
I want to check each message from each triggervalue column to see if message contains a string from array like string.
Here is what I've done:
I tried to merge every single array like string then send(triggermessage) where the same row of the found array contains, then checking for word.
connection.query(`SELECT * FROM triggervalue`, (err, rows) => {
let array = []
for(i = 0; i < rows.length; i++) {
let received = rows[i].jsonstring;
var intarray = received.replace(/^\[|\]$/g, "").split(", ");
array.concat(intarray)
// continue code here...
}
})
However, I can't get the triggermessage of the same row of found array. How would I go for it? I've been stuck here for quite a while... Sorry if this way of asking is wrong, thanks!
(Sorry if my english is bad)

Storetext from a table choice correct lines to store for Selenium Ide Ui Vision Kantu

I need to storetext all lines from a table where CODICE CATASTALE have a value
I add an image to show, I need to save all line in variable with storetext with this characteristic CODICE CATASTALE have a value, in the image I add 1 - 2 - 3 - 4 to explain line to store.
This is a relative storetext when CODICE CATASTALE have a value stored the line.
Here the page
nonsolocap.it/cap?k=56040
Image
After the execution such script in Selenium IDE table variable will contain data from the table. xpath_to_all_rows_with_CODICE_CATASTALE should be replaced with corresponding xpath.
store xpath count | xpath = xpath_to_all_rows_with_CODICE_CATASTALE | n
store | 0 | j
while | ${j} < ${n} |
store | | rowElement
store | 0 | i
while | ${i} < 7 |
store text | xpath = xpath_to_all_rows_with_CODICE_CATASTALE[${j}]/td[${i}] | element
execute script | if (${i} != 0) var arr = ${rowElement}; else var arr = []; var element = ${element}; arr.push(element); return arr; | rowElement
execute script | return Number(${i}) + 1; | i
end| |
execute script | if (${j} != 0) var arr = ${table}; else var arr = []; var rowElement = ${rowElement}; arr.push(rowElement); return arr; | table
execute script | return Number(${j}) + 1; | j
end| |
use scvSave command and give a name for the target for divide raws

Add more values in var while "X value" is lower than Y

I need to do a JSON Array using 3 or 4 colums but I can't fill the data using the "while" condition.
I have some Google Sheet Data which can have 3 or 4 columns, this data must be inside a JSON Array, for example:
|---------------------|------------------|---------------------|------------------|
| variable | condition | value | and/or |
|---------------------|------------------|---------------------|------------------|
| CPC | > | 100 | |
|---------------------|------------------|---------------------|------------------|
In this first example the 4th column is empty because we only have one row of data, so, the result must be:
["CPC",">",100]
if we have two rows (or more) of data, this should look like this:
|---------------------|------------------|---------------------|------------------|
| variable | condition | value | and/or |
|---------------------|------------------|---------------------|------------------|
| CPC | > | 100 | and |
|---------------------|------------------|---------------------|------------------|
| s_volume | < | 950 | and |
|---------------------|------------------|---------------------|------------------|
| s_volume | > | 100 | |
|---------------------|------------------|---------------------|------------------|
as you can see, the last row in the last column is empty, and the result should look like this:
["CPC",">",100],
"and",
["s_volume","<",950],
"and",
["s_volume",">",100]
Finally, this JSON array must me assigned to a variable.
I have tried with this:
//Get values from cells
var fil1 = ss.getSheetByName("app").getRange(row,4,1,1).getValue();
var fil2 = ss.getSheetByName("app").getRange(row,5,1,1).getValue();
var fil3 = ss.getSheetByName("app").getRange(row,6,1,1).getValue();
var fil4 = ss.getSheetByName("app").getRange(row,7,1,1).getValue();
//Count how many rows with data exist
var coldat = ss.getSheetByName("app").getRange("D1:D").getValues();
var coldats = coldat.filter(String).length;
var jsonarr = [fil1, fil2, fil3]
//loop para aƱadir nuevos filtros
while (row < coldats) {
fil4,[fil1,fil2,fil3];
row++;
};
Apparently with my code the var "jsonarr" is filled only with the first row, ignoring any number of rows below.
I have tried with several tutorials and array methods to make this JSON Object, but I just can't get the correct answer. I really sorry for this newbie question, I'm not expert in coding, just a geek that do some work and is learning the very basics.
This answer is offered to assist the OP to bring together a range of issues identified in the OP's original code. I have left a number of Logger statements in the answer code that the OP can use to identify values at different stages of the code, assist with troubleshooting, and as an aid to skill development.
The results of the code is contained in the variable fildata. Based on the sample data, the value is:
["CPC",">",100],"and",["s_volume","<",950],"and",["s_volume",">",100]
How this is exported is up to the OP.
The OP is trying to create a data array (non-complying JSON) for data in a spreadsheet as input to another system.
The design of the OP's code meant that it retrieved only one row of data, and it could never build up the array as expected. The OP's code is the basis of the answer, but there are several key changes:
Moved coldat and coldats to the top of the code so that the coldats could be used in defining the data range.
Retrieved a single data range (getRange(2, 4, coldats, 4)) and used 'getValues()' only once.
Created a variable to hold the results of code
Looped through the data row-by-row
For each row, evaluated whether Column G ("and/or" column) contained a value. Depending on the result, included Column G in the results for that row.
Built up the results by row-by-row increment.
function so54394711() {
// setup spreadsheet
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("app");
//Count how many rows with data exist
var coldat = sheet.getRange("D2:D").getValues();
var coldats = coldat.filter(String).length;
//Logger.log("DEBUG: Number of rows of data = "+coldats); //DEBUG
// establish the data range and values
var range = sheet.getRange(2, 4, coldats, 4);
//Logger.log("DEBUG: range = "+range.getA1Notation());//DEBUG
var values = range.getValues();
//Logger.log("DEBUG: values: "+ values);//DEBUG
// create a variable to hold the results
var fildata = "";
//loop through the data by row, build the results line-by-line
for (i = 0; i < coldats; i++) {
var filD = values[i][0];
var filE = values[i][1];
var filF = values[i][2];
var filG = values[i][3];
// test if column G contains a value
if (filG.length == 0) {
// array is empty
fildata += '[' + '"' + filD + '","' + filE + '",' + filF + ']';
//Logger.log("DEBUG: G=MT, fildata = "+fildata);//DEBUG
} else {
//array not empty
fildata += '[' + '"' + filD + '","' + filE + '",' + filF + ']' + ',"' + filG + '",';
//Logger.log("DEBUG: G<>MT, fildata = "+fildata);//DEBUG
}
// Logger.log("DEBUG: fildata = "+fildata);//DEBUG
}
}

Finding next empty row after a particular "Header" row

I have just started trying out the script editor of the Google Sheets.
Here is what I am trying to do:
I have a few "headers" in Sheet A. I will name them Header A, B, and C.
1 | Header A
2 | text 1
3 | text 2
4 | (empty row)
5 | Header B
6 | text 1
7 | text 2
8 | (empty row)
9 | Header C
10 | text 1
11 | text 2
Sheet B
1 | text 1 | date | Header A
2 | text 2 | date | Header B
3 | text 3 | date | Header B
4 | text 4 | date | Header C
5 | text 5 | date | Header A
When I update my data on Sheet B, it will be automatically be updated on Sheet A based on my custom attributes in Sheet B. I need it to be able to update the data on Sheet B onto Sheet A's empty row after the specific Headers.
Currently I am stuck at getting the next empty row in Sheet A. I am able to get the row that my Headers are in but I couldn't find any help online finding the next empty row after each specific Headers.
I could not find any classes that is provided. All I can see is getLastRow which is not what I want. I wonder can this be done?
Below is my current code:
function getScheduleStatus(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var name = ss.getSheetByName("Production Schedule");
var rng = name.getDataRange();
var last_row = rng.getLastRow();
var data = rng.getValues();
var str_upcoming = "upcoming"
var rows = [];
for (var i=0; i < data.length; i++) {
if (data[i][0].toLowerCase() == str_upcoming) {
Logger.log("true");
rows.push(i);
}
}
var row = Number(rows)+Number(rng.getRow());
Logger.log(row);
}
Currently I am able to find the Header as well as getting the row number.
Hope you guys can understand.
Take a look at Faster way to find the first empty row; the answers there can be adapted to your situation.
The fastest solution there was Don Kirby's, and since you have a single column of data, it is ideal. We just need to change it to start searching from a particular headerRow!
/**
* Search column A starting at the given row, to find
* the first following empty row. Uses spreadsheet row numbers.
* From: https://stackoverflow.com/a/38194740/1677912
*
* #param {Number} headerRow Row number to start search at.
*
* #returns {Number} Target empty row.
*/
function getFirstEmptyRowAfter(headerRow) {
var spr = SpreadsheetApp.getActiveSpreadsheet();
var column = spr.getRange('A:A');
var values = column.getValues(); // get all data in one call
var ct = headerRow; // Start at row after headerRow (0-adjusted)
while ( values[ct][0] != "" ) {
ct++;
}
return (ct + 1); // (1-adjusted)
}

Search Google Spreadsheet for same value and append in next column in GAS

I've got a Google Spreadsheet which looks like this:
ID | winkelName | 26/05/2015 |
1 | Foo | |
2 | Bar | |
3 | Foo2 | |
4 | Bar2 | |
I'm trying to read and write an array of objects with the following structure:
history[i].storeName
history[i].checkIns
What I would like to do is to write all the number of checkins (with the same winkelName) on the same row under the column date (26/05/2015). But I'm still stuck what is the best way to achieve this?
This is my first attempt:
function writeHistory(history) {
var sheet = historySheet.getSheets()[0];
historySheet.setActiveSheet(sheet);
var nextRow = sheet.getLastRow(); // get next row
var rows = sheet.getDataRange().getValues();
var lastColumn = sheet.getLastColumn();
sheet.insertColumnAfter(lastColumn);
lastColumn++;
sheet.getRange(1, lastColumn).setValue(new Date());
var column = sheet.getLastColumn();
for(i in rows) {
if(i != 0) {
if(rows[i][1] == history[i].winkelName) {
sheet.getRange(i, column).setValue(history[i].checkIns); // this is not fully working
}
}
}
}
In a Google spreadsheet you can write a range of cells at once. To do so, create a multi dimensional array with one column and for each row another dimension and within each row a dimension for each cell you want to write.
Loop through your checkings, set the cell values in your array and write the values using sheet.getRange(1,column-index).setValue([your array]);
Also check: Google's best practices on dealing with range values