I have this code. I want to loop through the array and create a new doc for each entry. If I manually set the loop length to the number of rows it works fine. I want to set it to loop for the length of the array. However the .length property always returns null. What am I missing. I have also tried for each loops with no luck.
function createDocument()
{
//var headers = Sheets.Spreadsheets.Values.get('fileID', 'A1:Z1');
var studentHistory = Sheets.Spreadsheets.Values.get('fileID', 'A2:Z200');
var templateId = 'fileID';
var documentId;
var dstFolder = DriveApp.getFolderById('folderID');
var length = studentHistory.length;
Logger.log(studentHistory);
Logger.log(length);
//Loop through rows in sheet
for (var i = 0; i < length; i++){
//Get values from sheet row
var date = studentHistory.values[i][0];
var studentName = studentHistory.values[i][1];
var dob = studentHistory.values[i][2];
var pcDoctor = studentHistory.values[i][3];
var address = studentHistory.values[i][4];
var fgName = studentHistory.values[i][5];
var mgName = studentHistory.values[i][6];
var phoneMom = studentHistory.values[i][7];
var phoneDad = studentHistory.values[i][8];
var empMom = studentHistory.values[i][9];
var empDad = studentHistory.values[i][10];
var livesWith = studentHistory.values[i][11];
var childrenInHome = studentHistory.values[i][12];
var childrenNotInHome = studentHistory.values[i][13];
var othersInHome = studentHistory.values[i][14];
var illnesses = studentHistory.values[i][15];
var illnessDetails = studentHistory.values[i][16];
var hospitalizations = studentHistory.values[i][17];
var hospDetails = studentHistory.values[i][18];
var trauma = studentHistory.values[i][19];
var traumaDetails = studentHistory.values[i][20];
var injuries = studentHistory.values[i][21];
var injuryDetails = studentHistory.values[i][22];
var medications = studentHistory.values[i][23];
var additionalComments = studentHistory.values[i][24];
var otherSchools = studentHistory.values[i][25];
//Make a copy of the template file
documentId = DriveApp.getFileById(templateId).makeCopy(dstFolder).getId();
//Change name of newly created document
DriveApp.getFileById(documentId).setName('SocialHistory_' + studentName + '_' + date);
var body = DocumentApp.openById(documentId).getBody();
//Insert values
body.replaceText('<<date>>', date);
body.replaceText('<<studentName>>', studentName);
body.replaceText('<<dob>>', dob);
body.replaceText('<<pcDoctor>>', pcDoctor);
body.replaceText('<<address>>', address);
body.replaceText('<<fgName>>', fgName);
body.replaceText('<<mgName>>', mgName);
body.replaceText('<<phoneMom>>', phoneMom);
body.replaceText('<<phoneDad>>', phoneDad);
body.replaceText('<<empMom>>', empMom);
body.replaceText('<<empDad>>', empDad);
body.replaceText('<<livesWithe>>', livesWith);
body.replaceText('<<childrenInHome>>', childrenInHome);
body.replaceText('<<childrenNotInHome>>', childrenNotInHome);
body.replaceText('<<othersInHome>>', othersInHome);
body.replaceText('<<illnesses>>', illnesses);
body.replaceText('<<illnessDetails>>', illnessDetails);
body.replaceText('<<hospitalizations>>', hospitalizations);
body.replaceText('<<hospDetails>>', hospDetails);
body.replaceText('<<trauma>>', trauma);
body.replaceText('<<traumaDetails>>', traumaDetails);
body.replaceText('<<injuries>>', injuries);
body.replaceText('<<injuryDetails>>', injuryDetails);
body.replaceText('<<medications>>', medications);
body.replaceText('<<additionalComments>>', additionalComments);
body.replaceText('<<otherSchools>>', otherSchools);
}
}
studentHistory.values is the array.
Therefore, try this instead to get the length:
var length = studentHistory.values.length;
Solution
I see you are using Advanced Google Services to call the Sheets API. This Apps Script class allows you to call the Google APIs directly from your script handling automatically the authorization process.
However it doesn't work as the built in Classes that are available for example inside the SpreadsheetApp wrapper.
Your request will return an HTTP-like response following these specifications:
{
"range": string,
"majorDimension": enum (Dimension),
"values": [
array
]
}
You will need to parse these responses in order to achieve the desired result.
Proposed modification
function createDocument()
{
//var headers = Sheets.Spreadsheets.Values.get('fileID', 'A1:Z1');
var studentHistory = Sheets.Spreadsheets.Values.get('fileID', 'A2:Z200');
var templateId = 'fileID';
var documentId;
var dstFolder = DriveApp.getFolderById('folderID');
var length = studentHistory.values.length;
...
Reference
Google Sheets API
Advanced Google Services
Related
I have read all the previous posts and I have a similiar subjetc that I can't solve. I have to copy/paste a Google Sheets (two sheets, 'GENERAL', 'VALEUR') document.
I have won to write a code to copy/paste : 1 document (source) ==to==> 1 document (destination)
function expCalc(){
copypaste_GENERAL();
copypaste_VALEUR();
}
function copypaste_GENERAL() {
var source_G = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xTBgfI-yy30GHm-LpsUWWoLRACNk5rdc81DPKGyS9fw/edit#gid=0');
var sourceSheet_G = source_G.getSheetByName('GENERAL');
var sourceRange_G = sourceSheet_G.getDataRange();
var sourceValues_G = sourceRange_G.getValues();
var tempSheet_G = source_G.getSheetByName('TEMP_GENERAL');
var tempRange_G = tempSheet_G.getRange('A1:DU11');
var destination_G = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1kFKaNOc8JbRM63tb24QB3_fJms5vnQbZj2lOYsoh0CA/edit#gid=1580219321');
var destSheet_G = destination_G.getSheetByName('GENERAL');
sourceRange_G.copyTo(tempRange_G); // paste all formats?, broken references
tempRange_G.offset(0, 0, sourceValues_G.length, sourceValues_G[0].length)
.setValues(sourceValues_G); // paste all values (over broken refs)
copydSheet = tempSheet_G.copyTo(destination_G); // now copy temp sheet to another ss
copydSheet.getDataRange().copyTo(destSheet_G.getDataRange());
destination_G.deleteSheet(copydSheet); //delete copydSheet
}
function copypaste_VALEUR() {
var source_V = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xTBgfI-yy30GHm-LpsUWWoLRACNk5rdc81DPKGyS9fw/edit#gid=0');
var sourceSheet_V = source_V.getSheetByName('VALEUR');
var sourceRange_V = sourceSheet_V.getDataRange();
var sourceValues_V = sourceRange_V.getValues();
var tempSheet_V = source_V.getSheetByName('TEMP_VALEUR');
var tempRange_V = tempSheet_V.getRange('A1:I255');
var destination_V = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1kFKaNOc8JbRM63tb24QB3_fJms5vnQbZj2lOYsoh0CA/edit#gid=1580219321');
var destSheet_V = destination_V.getSheetByName('VALEUR');
sourceRange_V.copyTo(tempRange_V); // paste all formats?, broken references
tempRange_V.offset(0, 0, sourceValues_V.length, sourceValues_V[0].length)
.setValues(sourceValues_V); // paste all values (over broken refs)
copydSheet = tempSheet_V.copyTo(destination_V); // now copy temp sheet to another ss
copydSheet.getDataRange().copyTo(destSheet_V.getDataRange());
destination_V.deleteSheet(copydSheet); //delete copydSheet
}
but I can't write a code to copy/paste : 1 document (source) ==to==> MANY (more than 1) documents (destination) according to a list of URLs (here, example only on 2 URLs)
Here is my test code (using only t'GENERAL' sheet for this present test)
function copypaste_GENERAL() {
var source = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xTBgfI-yy30GHm-LpsUWWoLRACNk5rdc81DPKGyS9fw/edit#gid=0');
var sourceSheet = source.getSheetByName('GENERAL');
var sourceRange = sourceSheet.getDataRange();
var sourceValues = sourceRange.getValues();
var tempSheet = source.getSheetByName('TEMP_GENERAL');
var tempRange = tempSheet.getRange('A1:DU11');
var destSpreadUrl = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1kFKaNOc8JbRM63tb24QB3_fJms5vnQbZj2lOYsoh0CA/edit#gid=1580219321');
var destSheetUrl = destSpreadUrl.getSheetByName('URLTST');
var destSheet_G = destSpreadUrl.getSheetByName('GENERAL');
var urlessai = destSheetUrl.getRange("D2:D3").getValues();
for (var row = 1; row = 3; row++) {
if (urlessai[row] != '') {
sourceRange.copyTo(tempRange); // paste all formats?, broken references
tempRange.offset(0, 0, sourceValues.length, sourceValues[0].length)
.setValues(sourceValues); // paste all values (over broken refs)
copydSheet = tempSheet.copyTo(destSpreadUrl); // now copy temp sheet to another ss
copydSheet.getDataRange().copyTo(destSheet_G.getDataRange());
destSpreadUrl.deleteSheet(copydSheet); //delete copydSheet
};
};
};
Please, can you help me to find a solution to write this copy/paste loop on a list of URLs (for x users) ?
Thanks in advance !
Philippe
This is probably not exactly what you want but I think it's close and I'm willing to tweak it.
function copySrcDes() {
const ss = SpreadsheetApp.getActive();
const locs = [{srcid:"1xTBgfI-yy30GHm-LpsUWWoLRACNk5rdc81DPKGyS9fw",desid:"1kFKaNOc8JbRM63tb24QB3_fJms5vnQbZj2lOYsoh0CA",shts:["GENERAL"]},{srcid:"1xTBgfI-yy30GHm-LpsUWWoLRACNk5rdc81DPKGyS9fw",desid:"1kFKaNOc8JbRM63tb24QB3_fJms5vnQbZj2lOYsoh0CA",shts:["VALEUR"]}];
locs.forEach(obj => {
let sss = SpreadsheetApp.openById(obj.srcid);
let dss = SpreadsheetApp.openById(obj.desid);
obj.shts.forEach(n => {
let ssh = sss.getSheetByName(n);
let dsh = dss.getSheetByName(n);
let vs = ssh.getDataRange().getValues();
dsh.getRange(1,1,vs.length,vs[0].length).setValues(vs);
});
});
}
In google sheets using the Coinmarketcap.com API I am trying to download data.
For this purpose, I have a loop in which I want to iterate subsequent names from the previously created table.
var listaCrypto = "BTC,ETH,ADA";
var tabCrypto = listaCrypto.split(",");
for (var i = 1; tabCrypto[i]; i++) {
var url='https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?symbol='+tabCrypto[i];
var result= UrlFetchApp.fetch(url, requestOptions);
var txt= result.getContentText();
var d=JSON.parse(txt);
lista1.getRange(start_row + rankBTC, 1).setValue(d.data.tabCrypto[i].name); //<-- this doesn't
lista1.getRange(start_row + rankBTC, 2).setValue(d.data.BTC.name); //<-- this line works
}
You can use this syntax object["property_name"] to retrieve a property property_name from object
var listaCrypto = "BTC,ETH,ADA";
var tabCrypto = listaCrypto.split(",");
for (var i = 0; i<tabCrypto.length; i++) {
var symbol = tabCrypto[i];
var url='https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?symbol='+tabCrypto[i];
var result= UrlFetchApp.fetch(url, requestOptions);
var txt= result.getContentText();
var d=JSON.parse(txt);
lista1.getRange(start_row + rankBTC, 1).setValue(d.data[symbol].name); //<-- this doesn't
lista1.getRange(start_row + rankBTC, 2).setValue(d.data.BTC.name); //<-- this line works
}
I've been searching for the answer to this question but have so far been unable to piece together the answer. Please explain any answer you have in really simple terms as I'm fairly new to GAS and RegEx. I've got most of the syntax down but the execution of it in GAS is giving me a hard time.
Basically, I want to write a script that, when the spreadsheet is edited, checks which rows have yet to be merged. Then, on those rows, creates a copy of a template Google Doc and names the document based on the spreadsheet data. From there (this is the hard part), I need it to replace merge tags in the template with the data from the spreadsheet.
The tags in the templates I'll be using look like this: <<mergeTag>>
My idea was to match the whole tag, and replace it with data from the spreadsheet that exists in the column with the same name as what's inside the "<<>>". Ex: <<FooBar>> would be replaced with the data from the column named FooBar. It would obviously be from the current row that needs the merging.
After that, all that's left is to send an email (a few more row-specific personalization) with that document attached (sometimes as a PDF) with the body of the message coming from an HTML file elsewhere in the project.
This is the whole thing I have so far (notice the placeholders here and there that I can personalize for each spreadsheet I use this for):
function onEdit() {
//SPREADSHEET GLOBAL VARIABLES
var ss = SpreadsheetApp.getActiveSpreadsheet();
//get only the merge sheet
var sheet = ss.getSheetByName("Merge Data");
//get all values for later reference
var range = sheet.getActiveRange();
var values = range.getValues();
var lastRow = range.getLastRow();
var lastColumn = range.getLastColumn();
//get merge checker ranges
var urlColumn = range.getLastColumn();
var checkColumn = (urlColumn - 1);
var checkRow = range.getLastRow();
var checkRange = sheet.getRange(2, checkColumn, checkRow);
var check = checkRange.getBackgrounds();
//get template determination range (unique to each project)
var tempConditionRange = sheet.getRange(row, column);
var tempConditionCheck = tempConditionRange.getValues();
//set color variables for status cell
var red = "#FF0000";
var yellow = "#FFCC00";
var green = "#33CC33";
//////////////////////////////////////////////////////////
//DOC GLOBAL VARIABLES
var docTemplate1 = DriveApp.getFileById(id);
var docTemplate2 = DriveApp.getFileById(id);
var docTemplate3 = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
//////////////////////////////////////////////////////////
//EMAIL GLOBAL VARIABLES
var emailTag = ss.getRangeByName("Merge Data!EmailTag");
var personalizers = "";
var subject = "" + personalizers;
var emailBody = HtmlService.createHtmlOutputFromFile("Email Template");
//////////////////////////////////////////////////////////
// MERGE CODE
for (i = 0; i < check.length; i++) {
//for rows with data, check if they have already been merged
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, lastRow, (lastColumn - 2))
statusCell.setBackground(red);
//for rows with data, but not yet merged, perform the merge code
//////////////////////////////////////////////////////////
//DOC CREATION
//Determine which template to use
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate1;
}
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate2;
}
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate3;
}
//Create a copy of the template
//Rename the document using data from specific columns, at specific rows
//Move the doc to the correct folder
var docName = "";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = docCopy.getUrl();
var docToSend = DriveApp.getFileById(docId);
var docBody = DocumentApp.openById(docId).getBody();
Here's where I need the help
//Locate the Merge Tags
//Match Merge Tags to the column headers of the same name
//Replace the Merge Tags with the data from the matched column, from the correct row
function tagReplace() {
var tagMatch = "/(<{2}(\w+)>{2})/g";
}
statusCell.setBackground(yellow);
urlCell.setValue(docURL);
The rest is just finishing up the process
//////////////////////////////////////////////////////////
//EMAIL CREATION
//Create an email using an HTML template
//Use Merge Tags to personalize email
//Attach the doc we created to the email
//Send email to recipients based on data in the sheet
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Person McPerson",
attachments: [docToSend], //[docToSend.getAs(MIME.PDF)],
html: emailBody,
});
//////////////////////////////////////////////////////////
//CHECK ROW UPDATE
statusCell.setBackground(green);
}
}
}
My sheets all have a frozen first row that acts as the header row. All my columns will be consistently named the exact same thing as the tags (minus the <<>>).
How do I match the tags to the data?
EDIT
```````````````````
The solution did not work as described when I inserted it into my code as follows:
function formMerge() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Merge Data");
var urlColumn = sheet.getMaxColumns();
var checkColumn = urlColumn - 1;
var lastRow = ss.getSheetByName("Form Responses").getLastRow();
var values = sheet.getDataRange().getValues();
var headers = values[0];
var urlRange = sheet.getRange(2, urlColumn, lastRow);
var checkRange = sheet.getRange(2, checkColumn, lastRow);
var check = checkRange.getBackgrounds();
var red = "#ff0404";
var yellow = "#ffec0a";
var green = "#3bec3b";
var docTemplate = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
// MERGE CODE
for (i = 0; i < check.length; i++) {
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, 1, (urlColumn - 2)).getValues();
var clientNameRange = sheet.getRange((i+2), 3);
var clientName = clientNameRange.getValue();
var dateRange = sheet.getRange((i+2), 2);
var datePreFormat = dateRange.getValue();
var timeZone = CalendarApp.getTimeZone();
var date = Utilities.formatDate(new Date(datePreFormat), timeZone, "MM/dd/yyyy");
statusCell.setBackground(red);
//EMAIL VARIABLES
var personalizers = clientName;
var subject = "Post Intake Report for " + personalizers;
var emailBody = "Please see the attached Google Doc for the Post Intake Report for " + clientName + ". The intake was performed on " + date + ".";
var emailTagRange = sheet.getRange((i+2), 24);
var emailTagValue = emailTagRange.getValue();
var emailTag = emailTagValue.split(", ");
//DOC CREATION
var docToUse = docTemplate;
var docName = "Post Intake Report - " + clientName + " [" + date + "]";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = docCopy.getUrl();
var docBody = DocumentApp.openById(docId).getBody().editAsText();
for (var j=0; j<headers.length; j++) {
var re = new RegExp("(<<"+headers[j]+">>)","g");
docBody.replaceText(re, dataRow[j]);
}
statusCell.setBackground(yellow);
urlCell.setValue(docURL);
//EMAIL CREATION
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Christopher Anderson",
attachments: [docCopy],
html: emailBody
});
statusCell.setBackground(green);
}
}
}
Build the RegExp for each tag on the fly, using the header values from your spreadsheet.
Use Body.replaceText() to perform the replacements.
var values = sheet.getDataRange().getValues();
var headers = values[0];
...
// Loop over all columns. Use header names to search for tags.
for (var col=0; col<headers.length; col++) {
// Build RegExp using column header
var re = new RegExp("(<{2}"+headers[col]+">{2})","g");
// Replace tags with data from this column in dataRow
body.replaceText(re, dataRow[col]);
}
This snippet will operate on a single row; the first couple of declarations should appear outside of your row loop. The column looping is then done after you've created and opened the new document, and obtained the body object.
It loops over all the columns in the spreadsheet, using the header names to find the tags you've defined, and replaces them with the corresponding cell contents for the current row.
I generate an html table using YUI/JavaScript. I am now trying to go through and store the information that is generated by looking at each item in the table using a for loop.
var savedata = function(){
var tabledata = Y.one("#generatedtable")._node;
var jData = [];
for (var r in tabledata.rows){
var samplerow = {};
samplerow.timestamp = r.cells[0].innerHTML;
samplerow.volts = r.cells[1].innerHTML;
samplerow.amps = r.cells[2].innerHTML;
samplerow.kW = r.cells[3].innerHTML;
samplerow.kWh = r.cells[4].innerHTML;
samplerow.sessionid = r.cells[5].innerHTML;
jData.push(samplerow);
}
};
using Chrome developer tools I can see that Y.one("#generatedtable")._node.rows gives me an HTMLcollection of [X]. This signifies the number of rows that were created by my previous function. Row[0] is just headers and I want to skip over this row. The loop fails on the
samplerow.timestamp = r.cells[0].innerHTML;
line. How should I structure this for loop to go through rows[0] to [X] to store in my JSON Data variable?
var savedata = function(){
var tabledata = Y.one("#generatedtable")._node;
var jData = [];
var i = 1;
var length = tabledata.rows.length
while (i<length){
var samplerow = {};
var r = tabledata.rows[i];
samplerow.timestamp = r.cells[0].innerHTML;
samplerow.volts = r.cells[1].innerHTML;
samplerow.amps = r.cells[2].innerHTML;
samplerow.kW = r.cells[3].innerHTML;
samplerow.kWh = r.cells[4].innerHTML;
jData.push(samplerow);
i++;
}
alert(jData);
};
Please check the script below.
Dynamic form, so the script also dynamic, I have to calculate when the form data changes. during this i am getting some problem.
am getting the value from the variable Final_price1, Final_price2 .....,Final_price7, Final_price8 and then am calculating the total of those.
During this calculation, am concatenating the following concat("Final_price",i); to get the values of the above. This concatenated correctly, but the above variables values are not coming. I dont know why the values are not getting there. So check the script and update me.
function assign_body()
{
var a_7= document.getElementById("option[280]").value;
var spl_7 = a_7.split("_");
//alert(spl);
var cr_7 = spl_7[1];
var operator3_7 = cr_7.split("[");
var symbol7 = operator3_7[0];
var dtt_7 = operator3_7[1];
var myarr_7 = dtt_7.split("$");
var symbol_st_7 = myarr_7[1];
//alert(symbol_st);
//alert(symbol_s);
//var symbol_a = symbol_s.split("(");
//var symbol = symbol_a[1];
//alert(symbol);
var split_value_7 = myarr_7[1];
//alert(split_value);
var final_value_7 =symbol_st_7.split(".");
var Final_price7 =final_value_7[0];
var a_8= document.getElementById("option[281]").value;
var spl_8 = a_8.split("_");
//alert(spl);
var cr_8 = spl_8[1];
var operator3_8 = cr_8.split("[");
var symbol8 = operator3_8[0];
var dtt_8 = operator3_8[1];
var myarr_8 = dtt_8.split("$");
var symbol_st_8 = myarr_8[1];
//alert(symbol_st);
//alert(symbol_s);
//var symbol_a = symbol_s.split("(");
//var symbol = symbol_a[1];
//alert(symbol);
var split_value_8 = myarr_8[1];
//alert(split_value);
var final_value_8 =symbol_st_8.split(".");
var Final_price8 =final_value_8[0];
var j=8;
var total_amount=0;
for(var i=1; i<=j; i++)
{
final_prices=concat("Final_price",i);
alert(final_prices);
symbol_prices=concat("symbol",i);
alert(symbol_prices);
if(isNumber(final_prices)){
alert("number");
/*if(symbol_prices =='+') {
alert("plus");
var total_amount+=parseInt(original_prices)+parseInt(final_prices);
calculated_price_element.innerHTML=total_amount;
alert(total_amount);
} else if(symbol_prices =='-') {
alert("minus");
var total_amount+=parseInt(original_prices)-parseInt(final_prices);
calculated_price_element.innerHTML=total_amount;
alert(total_amount);
}*/
//alert('test');
}
}
}