Changes made in one spreadsheet must get reflected in another spreadsheet - google-apps-script

I have a google spreadsheet "shared" where it consists of all the bill of materials. I want to keep another spreadsheet "master" such that only owner can access that. Any data inserted in the shared spreadsheet should get reflected in master spreadsheet, but if we edit shared spreadsheet it should not get reflected in master spreadsheet.
Any help would be appreciated.

Well it depends on what you mean by "changes", but you could put =Master!A1 in cell A1 of the slave sheet, then drag the bottom right corner all the way down, then drag the bottom right corner of that selection all the way across. So cell D8 will have =Master!D8, and so on.

Google Spreadsheets does have a scripting capability. It also has a public gallery script.
image http://img593.imageshack.us/img593/5410/screenshot20110720at736.png
One of the public scripts is edit to another spreadsheet
edit to another spreadsheet
update in another spreadsheet the changes in the current one
ticcaje (at) gmail.com
image http://img97.imageshack.us/img97/240/picture1nns.png
unfortunately it has not been updated in some time, and after looking at the code I don't think it was ever actually completed, as there is a dialog message and then a return statement.
image http://img718.imageshack.us/img718/5264/pictureja.png
I think this could be a really useful script and so I've done a little editing with it, but actually there are no comments in it, and I don't have the time to get it working 100% right now, but I wanted to post it here in hopes that somebody could actually pick it up and run with it.
function onEdit(){
var sourceSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var targetSpreadsheet = SpreadsheetApp.openById('0AntUWac3dtkUac3dtnhTjMwac3dtVjBiac3dtOXcac3dt'); //put in your spreadsheet key here
var sourcesSheet = sourceSpreadsheet.getSheets()[0];
var targetSheet = targetSpreadsheet.getSheets()[0];
var currentSourceCellIndex = SpreadsheetApp.getActiveRange().getRow(); //ActiveCell().getValues();
var selectedCell = SpreadsheetApp.getActiveSpreadsheet().getActiveSelection().getA1Notation();
var targetRowsCount = targetSheet.getLastRow();
var targetColumns = sourcesSheet.getLastColumn();
var targetRange = targetSheet.getRange(1, 1, targetRowsCount, targetColumns);
var targetSources = targetRange.getValues();
var sourceRows = sourcesSheet.getLastRow();
var sourceColumns = sourcesSheet.getLastColumn();
var sourcesRange = sourcesSheet.getRange(1, 1, sourceRows, sourceColumns);
var sources = sourcesRange.getValues();
var compareName = sources[currentSourceCellIndex-1][0];
return;
//Browser.msgBox("currentSourceCell: "+sources[currentSourceCellIndex-1][0]);return; // ActiveCell()
//Browser.msgBox("currentSourceCell: "+targetRowsCount);
// return;
for (var i = 1; i < targetRowsCount; ++i) {
if (targetSources[i-1][0] == compareName){
targetSheet.deleteRow(i);
break;
}
}
// var sourceRows = sourcesSheet.getLastRow();
// var sourceColumns = sourcesSheet.getLastColumn();
// var sourcesRange = sourcesSheet.getRange(1, 1, sourceRows, sourceColumns);
// var sources = sourcesRange.getValues();
//if ((sources[sourceRows-1][0] == "")||(sources[sourceRows-1][1] == "") ||(sources[sourceRows-1][2] == "") || (sources[sourceRows-1][3] == "") || (sources[sourceRows-1][4] == "") || (sources[sourceRows-1][5] == ""))
//return;
//currentSourceCell = sourceSheet.getActiveCell();
rowToInsert = targetSheet.getLastRow();
targetSheet.insertRowAfter(rowToInsert);
var insertRange = targetSheet.getRange(rowToInsert + 1, 1, 1, targetSheet.getLastColumn());
var kolonnen = [];
var tbText = [];
for (var i = 1; i < 16; ++i) {
kolonnen.push(i);
tbText.push(sources[sourceRows-1][i-1]);
}
//Browser.msgBox("source is: "+tbText);return;
for (j = 0; j < kolonnen.length; j++) {
var zellRange = targetSheet.getRange(rowToInsert+1, kolonnen[j], 1, 1);
zellRange.setValue(tbText[j]);
}
}
The original code can be accessed by editing the script, but if you want it I'll just go ahead and post it here, too:
function onEdito() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {
name: "go",
functionName: "insertRow"
}
// ,
// {
// name: "Build Journal",
// functionName: "collectJournal"
// }
];
ss.addMenu("pastePlus", menuEntries);
}
function onEdit(){
var sourceSpreadsheetName = Browser.inputBox("source spreadsheet");
//var sourceSpreadsheetName = SpreadsheetApp.getActiveSpreadsheet().getName();
var files = DocsList.getFilesByType("spreadsheet");
//var files = SpreadsheetApp;
Browser.msgBox("currentSourceCell: " +files);
//var sourceSpreadsheet;
for (var i = 0; i < files.length; ++i) {
var filename = files[i].getName();
if (filename == sourceSpreadsheetName) {
var sourceSpreadsheet = SpreadsheetApp.openById(files[i].getId());
var sheets = sourceSpreadsheet.getSheets();
var sourcesSheet = sheets[1];
break;
}
}
var targetSpreadsheetName = "Probando Script"; //DocsList.getFilesByType("spreadsheet");
//var targetSpreadsheet;
for (var i = 0; i < files.length; ++i) {
var filename = files[i].getName();
if (filename == targetSpreadsheetName) {
var targetSpreadsheet = SpreadsheetApp.openById(files[i].getId());
var sheets = targetSpreadsheet.getSheets();
var targetSheet = sheets[1];
break;
}
}
var currentSourceCellIndex = SpreadsheetApp.getActiveRange().getRow(); //ActiveCell().getValues();
var selectedCell = SpreadsheetApp.getActiveSpreadsheet().getActiveSelection().getA1Notation();
var targetRowsCount = targetSheet.getLastRow();
var targetColumns = sourcesSheet.getLastColumn();
var targetRange = targetSheet.getRange(1, 1, targetRowsCount, targetColumns);
var targetSources = targetRange.getValues();
var sourceRows = sourcesSheet.getLastRow();
var sourceColumns = sourcesSheet.getLastColumn();
var sourcesRange = sourcesSheet.getRange(1, 1, sourceRows, sourceColumns);
var sources = sourcesRange.getValues();
var compareName = sources[currentSourceCellIndex-1][0];
//Browser.msgBox("currentSourceCell: "+sources[currentSourceCellIndex-1][0]);return;
Browser.msgBox("currentSourceCell: "+targetRowsCount);return;
for (var i = 1; i < targetRowsCount; ++i) {
if (targetSources[i-1][0] == compareName){
targetSheet.deleteRow(i);
break;
}
}
var sourceRows = sourcesSheet.getLastRow();
var sourceColumns = sourcesSheet.getLastColumn();
var sourcesRange = sourcesSheet.getRange(1, 1, sourceRows, sourceColumns);
var sources = sourcesRange.getValues();
//if ((sources[sourceRows-1][0] == "")||(sources[sourceRows-1][1] == "") ||(sources[sourceRows-1][2] == "") || (sources[sourceRows-1][3] == "") || (sources[sourceRows-1][4] == "") || (sources[sourceRows-1][5] == ""))
//return;
//currentSourceCell = sourceSheet.getActiveCell();
rowToInsert = targetSheet.getLastRow();
targetSheet.insertRowAfter(rowToInsert);
var insertRange = targetSheet.getRange(rowToInsert + 1, 1, 1, targetSheet.getLastColumn());
var kolonnen = [];
var tbText = [];
for (var i = 1; i < 16; ++i) {
kolonnen.push(i);
tbText.push(sources[sourceRows-1][i-1]);
}
//Browser.msgBox("source is: "+tbText);return;
for (j = 0; j < kolonnen.length; j++) {
var zellRange = targetSheet.getRange(rowToInsert+1, kolonnen[j], 1, 1);
zellRange.setValue(tbText[j]);
}
}

Related

Creating sheets with from master sheet

I have a sheet named form responses which gets input from google
forms,Then I created sheets with names from Column C which is
employee code and append all the respective rows from form responses
to the newly created sheets.
Now I have sheets with name as employee code ( which is in column c of the sheet). Then I want to create secondary sheets from this master sheet(sheets with name as employee code) whose name is using the column E value as attached to the Employee code.for eg : if Emp code is 10003825 and value in column E is ASR, the sheet name should be 10001515ASR.
In Column E there are only 4 values ADC,ASR ACC,RSR. let the master sheet(sheets with name as employee code) retain ADC rows always while when other rows containing ASR,ACC,RSR comes append the respective row to the newly created sheet(ie if ASR the row goes to 10001515ASR).
I have shown my present sheet and expected output
The code I developed is shown below:
function switchSheet(){
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheets = activeSpreadsheet.getSheets();
for (var i = 1; i < sheets.length; i++) {
var p = sheets[i].getSheetName();
sheetCreateChannel(p);
}
}
function sheetCreateChannel(ss){
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = activeSpreadsheet.getSheetByName(ss);
var getNames = sheet1.getDataRange().getValues();
getNames.shift();
var sheets = activeSpreadsheet.getSheets();
var sheetsObj = {};
for (var i = 0; i < sheets.length; i++) {
sheetsObj[sheets[i].getSheetName()] = sheets[i];
for (var i = 0; i < getNames.length; i++) {
var r = getNames[i];
if (r[4].toString()== "ASR"&& !((ss+(r[4])) in sheetsObj)) {
var newSheet = activeSpreadsheet.insertSheet(ss + "ASR");
sheetsObj[ss+"ASR"] = newSheet;
}
else if (r[4].toString()== "ACC"&&!((ss+(r[4])) in sheetsObj)) {
var newSheet = activeSpreadsheet.insertSheet(ss + "ACC");
sheetsObj[ss+"ACC"] = newSheet;
}
else if (r[4].toString()== "RSR"&& !((ss+(r[4])) in sheetsObj)) {
var newSheet = activeSpreadsheet.insertSheet(ss + "RSR");
sheetsObj[ss+"RSR"] = newSheet;
}
else {
break;
}
}
}
var deleteRows = 0;
for (var i = 0; i < getNames.length; i++) {
var r = getNames[i];
if (r[4].toString() != "") {
if ((ss+(r[4])) in sheetsObj) {
var Q =ss+(r[4]);
sheetsObj[Q].appendRow(r);
}
deleteRows = i + 2;
}
}
sheet1.getRange(2, 1, deleteRows - 1, sheet1.getLastColumn()).clearContent();
}
This code works fine for my above issue
function sheetCreate(){
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = activeSpreadsheet.getSheetByName("Form Responses 1");
var getNames = sheet1.getDataRange().getValues();
getNames.shift();
var sheets = activeSpreadsheet.getSheets();
var sheetsObj = {};
for (var i = 0; i < sheets.length; i++) {
sheetsObj[sheets[i].getSheetName()] = sheets[i];
}
var deleteRows = 0;
for (var i = 0; i < getNames.length; i++) {
var r = getNames[i];
var N=r[2].toString()+r[4].toString();
if (N != "") {
if (N in sheetsObj) {
sheetsObj[N].appendRow(r);
} else {
var newSheet = activeSpreadsheet.insertSheet((N));
var cell1 = newSheet.getRange("A1").setValue("Timestamp");
var cell2 = newSheet.getRange("B1").setValue("Score");
var cell3 = newSheet.getRange("C1").setValue("Employee ID");
var cell4 = newSheet.getRange("D1").setValue("Name of the ATCO");
var cell5 = newSheet.getRange("E1").setValue("The channel on which duty is performed ");
var cell6 = newSheet.getRange("F1").setValue("DATE on which duty is performed");
var cell7 = newSheet.getRange("G1").setValue("Total duration of duty done");
newSheet.appendRow(r);
sheetsObj[N] = newSheet;
}
deleteRows = i + 2;
}
}
sheet1.getRange(2, 1, deleteRows - 1, sheet1.getLastColumn()).clearContent();
}

Create an array of values that were looped through

I have a spreadsheet where each row in "MASTER" sheet is a task. It has checkboxes to check if it's done.
On another sheet, "Sin despachar", the data is filtered so that only the tasks which are not done show. There I have empty checkboxes to check when an incomplete task is completed.
I wrote a script so that when a button is pressed, it loops through the whole column in "Sin despachar" to see if checkboxes are checked, and for those that are, it changes the value in a master sheet.
I would like to have a confirmation pop up that mentions all the tasks it'll edit, but for that I need to somehow retrieve that list when the script runs, and I don't know how.
So what I need is to create an array or something else that contains the names of the tasks with the checkbox checked.
Does anyone know how to do this?
The task names are in column 4, and the checkboxes are in column 18.
Thanks in advance!!
function marcarEtiquetado() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sin despachar");
var sheetRange = s.getDataRange();
var sheetValues = sheetRange.getValues();
for (var i=sheetRange.getLastRow()-1; i>1; i--) {
// si valor en columna R (etiquetado) = TRUE
if ( sheetValues[i][17] === true) {
var checkboxRange = s.getRange(i, 18);
var usuariosRange = s.getRange(i, 3)
Logger.log(usuariosRange)
var targetSheet = ss.getSheetByName("*MASTER*");
var targetRow = sheetValues[i][1];
var targetRange = targetSheet.getRange( targetRow, 16);
var targetTS = targetSheet.getRange( targetRow, 17);
checkboxRange.setValue(false)
targetRange.setValue(true);
targetTS.setValue(new Date()).setNumberFormat("dd-mm-yy hh:mm")
} ;
}
s.getRange(3, 18, s.getLastRow()-2).setValue(false)
}
You use alerts to confirm for every checked box individually either and action shall be carried out.
Sample:
function marcarEtiquetado() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sin despachar");
var sheetRange = s.getDataRange();
var sheetValues = sheetRange.getValues();
var ui = SpreadsheetApp.getUi();
for (var i=sheetRange.getLastRow()-1; i>1; i--) {
// si valor en columna R (etiquetado) = TRUE
if ( sheetValues[i][17] === true) {
var checkboxRange = s.getRange(i, 18);
var usuariosRange = s.getRange(i, 3)
var targetSheet = ss.getSheetByName("*MASTER*");
var targetRow = sheetValues[i][1];
var targetRange = targetSheet.getRange(targetRow, 16);
var targetTS = targetSheet.getRange(targetRow, 17);
var response = ui.alert('Do you want to set the timestamp for row ' + (i+1) + '?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
checkboxRange.setValue(false)
targetRange.setValue(true);
SpreadsheetApp.getActiveSpreadsheet().toast("Timestamp will be set for row " + (i+1));
targetTS.setValue(new Date()).setNumberFormat("dd-mm-yy hh:mm")
} else {
SpreadsheetApp.getActiveSpreadsheet().toast("Timestamp will not be set for row " + (i+1));
}
} ;
}
s.getRange(3, 18, s.getLastRow()-2).setValue(false)
}
If this is not what you wanted and you prefer to have a single confirmation dialog for all checked boxes, you can implement a help array and string as following:
function marcarEtiquetado2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Sin despachar");
var sheetRange = s.getDataRange();
var sheetValues = sheetRange.getValues();
var ui = SpreadsheetApp.getUi();
var rowKeeper = [];
var rowArray = ['\n'];
for (var i=sheetRange.getLastRow()-1; i>1; i--) {
// si valor en columna R (etiquetado) = TRUE
if ( sheetValues[i][17] === true) {
rowKeeper.push(i);
rowArray.push(i+1);
}
}
for (k = 0; k < rowArray.length-4; k += 5) {
rowArray[k+4] = rowArray[k+4] + "\n";
}
var rowString = rowArray.join(" ");
Logger.log(rowString);
var response = ui.alert('Do you want to set the timestamp for rows ' + rowString + '?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
for (var j = 0; j < rowKeeper.length; j++){
var i = rowKeeper[j];
var checkboxRange = s.getRange(i, 18);
var usuariosRange = s.getRange(i, 3)
var targetSheet = ss.getSheetByName("*MASTER*");
var targetRow = sheetValues[i][1];
var targetRange = targetSheet.getRange(targetRow, 16);
var targetTS = targetSheet.getRange(targetRow, 17);
checkboxRange.setValue(false)
targetRange.setValue(true);
targetTS.setValue(new Date()).setNumberFormat("dd-mm-yy hh:mm")
}
} else {
SpreadsheetApp.getActiveSpreadsheet().toast("No action will be carried out");
}
s.getRange(3, 18, s.getLastRow()-2).setValue(false)
}

Google script to auto populate a form with conditional logic failing due to variable not being defined (even though it looks defined to me)

Below is a script written by Jordan Rhea and provided via github.
I am trying to follow its logic so that I can understand how to approach automatically populating a form with questions that have conditional logic flowing to different sections of a Google Form.
The code is breaking at line 35 "ReferenceError: form is not defined (line 35, file "RosterMaker")
Line 35 = var classSection = form.addPageBreakItem().setTitle(className).setGoToPage(FormApp.PageNavigationType.SUBMIT);
I'm sure this is a simple error, but I cannot figure it out.
var ssID = "something";
var formID = "something"
//SpreadsheetApp.openById(ssID).getSheetByName("db_type");
function rosterMaker() {
//spreadsheet id of the rosters
var SHEET_ID = SpreadsheetApp.getActive();
var ss = SpreadsheetApp.openById(ssID);
var form = FormApp.openById((formID));
//get only the sheets with 'Roster' in the title
var sheets = ss.getSheets()
.filter(function(sheet) {return sheet.getName().match(/Roster/gi);});
//add multiple choice item
var classSelect = form.addMultipleChoiceItem()
.setTitle('Choose a class');
Logger.log(classSelect);
//get the class choices for the multiple choice item
var classChoices = getClasses(sheets);
//assign the choices to the classSelect variable
classSelect.setChoices(classChoices);
}
function getClasses(sheets) {
var classChoices = [];
for(var i = 0; i < sheets.length; i++) {
var className = sheets[i].getName();
var classSection = form.addPageBreakItem()
.setTitle(className)
.setGoToPage(FormApp.PageNavigationType.SUBMIT);
var students = getStudents(sheets[i]);
var studentSelect = form.addCheckboxItem()
.setTitle(className + ' absent')
.setHelpText('Select the students who are absent from this class');
var studentChoices = [];
for(var j = 0; j < students.length; j++) {
studentChoices.push(studentSelect.createChoice(students[j]));
}
studentSelect.setChoices(studentChoices);
classChoices.push(classSelect.createChoice(className, classSection));
}
return classChoices;
}
function getStudents(sheet) {
var studentValues = sheet.getDataRange().getValues();
var students = [];
for(var i = 1; i < studentValues.length; i++) {
students.push(studentValues[i].join(' '));
}
return students;
}
Test this:
var ssID = "something";
var formID = "something";
function rosterMaker() {
var SHEET_ID = SpreadsheetApp.getActive();
var ss = SpreadsheetApp.openById(ssID);
var form = FormApp.openById((formID));
var sheets = ss.getSheets().filter(function(sheet) {return sheet.getName().match(/Roster/gi);});
var classSelect = form.addMultipleChoiceItem().setTitle('Choose a class');
var classChoices = getClasses(sheets,form);//modified
classSelect.setChoices(classChoices);
}
function getClasses(sheets,form) {//modified
var classChoices = [];
for(var i = 0; i < sheets.length; i++) {
var className = sheets[i].getName();
var classSection = form.addPageBreakItem().setTitle(className).setGoToPage(FormApp.PageNavigationType.SUBMIT);
var students = getStudents(sheets[i]);
var studentSelect = form.addCheckboxItem().setTitle(className + ' absent').setHelpText('Select the students who are absent from this class');
var studentChoices = [];
for(var j = 0; j < students.length; j++) {
studentChoices.push(studentSelect.createChoice(students[j]));
}
studentSelect.setChoices(studentChoices);
classChoices.push(classSelect.createChoice(className, classSection));
}
return classChoices;
}
function getStudents(sheet) {
var studentValues = sheet.getDataRange().getValues();
var students = [];
for(var i = 1; i < studentValues.length; i++) {
students.push(studentValues[i].join(' '));
}
return students;
}

How to create a new document from a template with placeholders

I'm trying to create a script that will create new documents from a template-document. Replace placeholders in the documents with data from the sheet based on a keyword search in a specific column. And then change the row's value in the specific column so that the row will not process when the script runs again.
I think I've got it right with the first keyword search, and the loop through the rows. But the last part to get the data to 'merge' to the placeholders I can't figure out how to. I just get the value "object Object" and other values in the document.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var lastColumn = s.getLastColumn();
function createDocFromSheet() {
var headers = getUpsertHeaders(s);//function is defined outside of this function
var statusColNum = headers.indexOf('Status')+1;
var row = getRowsData(s); //The function is defined outside this function.
for (var i=0; i<row.length; i++) {
var jobStatus = '';
if (row[i]['Status'] === '') {
//New: write the status to the correct row and column - this will be moved to the end when I get the rest right
var jobStatus = "Created";
s.getRange(i+2, statusColNum).setValue(jobStatus);
//Find the template and make a copy. Activate the body of the new file.
var templateFile = DriveApp.getFileById('1lkfmqsJMjjPujHqDqKtcDmL-5GMIxpOWTyCOaK29d2A');
var copyFile = templateFile.makeCopy()
var copyId = copyFile.getId()
var copyDoc = DocumentApp.openById(copyId)
var copyBody = copyDoc.getActiveSection()
//Find the rows Values as an object.
var rows = s.getRange(i+2,1,1,lastColumn)
var rowsValues = rows.getValues();
Logger.log(rowsValues)
//Until here I think it's okay but the last part?
//HOW TO replace the text???
for (var columnIndex = 0; columnIndex < lastColumn; columnIndex++) {
var headerValue = headerRow[columnIndex]
var rowValues = s.getActiveRange(i,columnIndex).getValues()
var activeCell = rowsValues[columnIndex]
//var activeCell = formatCell(activeCell);
Logger.log(columnIndex);
copyBody.replaceText('<<' + headerValue + '>>', activeCell)
}
Template doc : Link
Template sheet: Link
You can use the following GAS code to accomplish your goals:
var DESTINATION_FOLDER_ID = 'YOUR_DESTINATION_FOLDER_ID';
var TEMPLATE_FILE_ID = 'YOUR_TEMPLATE_FILE_ID';
function fillTemplates() {
var sheet = SpreadsheetApp.getActiveSheet();
var templateFile = DriveApp.getFileById(TEMPLATE_FILE_ID);
var values = sheet.getDataRange().getDisplayValues();
var destinationFolder = DriveApp.getFolderById(DESTINATION_FOLDER_ID);
for (var i=1; i<values.length; i++) {
var rowElements = values[i].length;
var fileStatus = values[i][rowElements-1];
if (fileStatus == 'Created') continue;
var fileName = values[i][0];
var newFile = templateFile.makeCopy(fileName, destinationFolder);
var fileToEdit = DocumentApp.openById(newFile.getId());
for (var j=1; j<rowElements-1; j++) {
var header = values[0][j];
var docBody = fileToEdit.getBody();
var patternToFind = Utilities.formatString('<<%s>>', header);
docBody.replaceText(patternToFind, values[i][j]);
}
sheet.getRange(i+1, rowElements).setValue('Created');
}
}
You only have to replace the 1st and 2nd lines as appropriate. Please do consider as well that the code will assume that the first column is the file name, and the last one the status. You can insert as many columns as you wish in between.
After some coding I ended up with this code to process everything automatic.
Again thanks to #carlesgg97.
The only thing I simply can't figure out now is how to generate the emailbody from the template with dynamic placeholders like in the document. How to generate the var patternToFind - but for the emailbody?
I've tried a for(var.... like in the document but the output doesn't replace the placeholders.
var DESTINATION_FOLDER_ID = '1inwFQPmUu1ekGGSB5OnWLc_8Ac80igK0';
var TEMPLATE_FILE_ID = '1lkfmqsJMjjPujHqDqKtcDmL-5GMIxpOWTyCOaK29d2A';
function fillTemplates() {
//Sheet variables
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
var values = sheet.getDataRange().getDisplayValues();
//Header variables
var headers = sheet.getDataRange().getValues().shift();
var idIndex = headers.indexOf('ID');
var nameIndex = headers.indexOf('Name');
var emailIndex = headers.indexOf('Email');
var subjectIndex = headers.indexOf('Subject');
var statusIndex = headers.indexOf('Status');
var fileNameIndex = headers.indexOf('File Name');
var filerIndex = headers.indexOf('Filer');
var birthIndex = headers.indexOf('Date of birth');
//Logger.log(statusIndex)
//Document Templates ID
var templateFile = DriveApp.getFileById(TEMPLATE_FILE_ID);
//Destination
var destinationFolder = DriveApp.getFolderById(DESTINATION_FOLDER_ID);
var templateTextHtml = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Email').getRange('D11').getValue();
//Run through the variables
for (var i=1; i<values.length; i++) {
//If first column is empty then stop
var index0 = values[i][0];
if(index0 == "") continue;
var rowElements = values[i].length;
var fileStatus = values[i][statusIndex];
//If the row already processed then stop
if (fileStatus == "Created") continue;
//If the row is not processed continue
//Define the new filename by the relevant Column
var fileName = values[i][fileNameIndex];
var newFile = templateFile.makeCopy(fileName, destinationFolder);
var fileToEdit = DocumentApp.openById(newFile.getId());
//Replace placeholders in the new document
for (var j=1; j<rowElements-1; j++) {
var header = values[0][j];
var docBody = fileToEdit.getBody();
var patternToFind = Utilities.formatString('{{%s}}', header);
docBody.replaceText(patternToFind, values[i][j]);
}
//Create the PDF file
fileToEdit.saveAndClose();
var newPdf = DriveApp.createFile(fileToEdit.getAs('application/pdf'));
DriveApp.getFolderById(DESTINATION_FOLDER_ID).addFile(newPdf);
DriveApp.getRootFolder().removeFile(newPdf);
newFile.setTrashed(true);
var newPdfUrl = newPdf.getUrl();
//Create the emailbody
var textBodyHtml = templateTextHtml.replace("{{Name}}",values[i][nameIndex]).replace("{{Date of birth}}",values[i][birthIndex]);
var textBodyPlain = textBodyHtml.replace(/\<br>/mg,"");
//Will send email to email Column
var email = values[i][emailIndex];
var emailSubject = values[i][idIndex]+" - "+values[i][fileNameIndex]+" - "+values[i][nameIndex];
MailApp.sendEmail(email,emailSubject,textBodyPlain,
{
htmlBody: textBodyHtml+
"<p>Automatic generated email</p>",
attachments: [newPdf],
});
sheet.getRange(i+1, filerIndex+1).setValue(newPdfUrl);
sheet.getRange(i+1, statusIndex+1).setValue('Created');
}//Close for (var i=1...
}

Google Apps Script Substring

In my spreadsheet I have a file path to an image stored in a sub folder. The image is stored like this because I am making an app for my employer using appsheet.com. They want this app developed using AppSheet, which does not allow images to be stored directly into the spreadsheets that are used to build these app.
The data stored in the spreadsheet must also be extracted and applied to a template and I am making a Google Apps Script to do this. I have a functional script which finds the template and extract the users chosen data row, but I cannot extract the image needed.
I have been trying to make a substring of the file path to get the file name, but I have been unable to do this.
In the block of code where I am trying to create the substring, I am getting an error on the line sig = signature.getText();. The error is TypeError: signature.getText is not a function (line 176, file "Code").
This is what the file path looks like Signatures/FT101.Signed (%SIGNED%).103735.png, and the substring I need would look like this FT101.Signed (%SIGNED%).103735.png
I have tried multiple methods that were provided by other questions asked on stack overflow as well as any potential methods available in the Google Apps Script reference.
The following function takes the users input from a prompt and uses it to find the desired row number. It then takes the data from that row and applies it to a template based on the category the data falls under.
var response = {};
var sign = "";
function chooseRowMethod(templateId){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var dataRange = sheet.getDataRange();
var values = dataRange.getValues();
var data = sheet.getRange(2, 2, 11, 18).getValues();//starting with row 2 and column 1 as our upper-left most column, get values from cells from 1 row down, and 15 columns along - hence (2,1,1,15)
var docTitle = sheet.getRange(2, 2, 11, 1).getValues();//this is grabbing the data in field B2
var docTitleTagNumber = sheet.getRange(2, 3, 11, 1).getValues();
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1;
var yyyy = today.getFullYear();
today = dd + '/' + mm + '/' + yyyy;
for(var i = 0; i < values.length; i++){
for(var j = 0; j < values[i].length; j++){
if(values[i][j] == response){
Logger.log(i);
var row = data[i - 1];
var docId = DriveApp.getFileById(templateId).makeCopy().getId();
var doc = DocumentApp.openById(docId);
var body = doc.getActiveSection();
body.replaceText("%SITEID%", row[0]);
body.replaceText("%TAG%", row[1]);
...
body.replaceText("%SAT%", row[14]);
var signature = sheet.getRange(2, 18, 11, 1).getValues();
var sig;
var sign = {};
for(var i = 0; i < values.length; i++){
for(var j = 0; j < values[i].length; j++){
if(values[i][j] == response){
sig = signature.getText();
sign[i][0] = sig.substring(sig.indexOf("/") + 1);
}
}
}
var sigFolder = DriveApp.getFolderById("1LiJKGjTbpvRZ5RrMTQoyTuAjrozA14FN");
var file = sigFolder.getFilesByName(sign);
var image = file.getId();
body.appendImage(image);
doc.saveAndClose();
var file = DriveApp.getFileById(doc.getId());
var newFolder = DriveApp.getFolderById("16wRGBVdV0OZ5YfKhqEQSFMsux-ekGCCa");
newFolder.addFile(file);
var newDocTitle = docTitle[i - 1][0];
var newDocTagNumber = docTitleTagNumber[i - 1][0];
doc.setName(newDocTitle + " " + newDocTagNumber + " " + today);
}
}
}
}
This is where I have been attempting to get the image.
var signature = sheet.getRange(2, 18, 11, 1).getValues();
var sig;
var sign = {};
for(var i = 0; i < values.length; i++){
for(var j = 0; j < values[i].length; j++){
if(values[i][j] == response){
sig = signature.getText();
sign[i][0] = sig.substring(sig.indexOf("/") + 1);
}
}
}
var sigFolder = DriveApp.getFolderById("1LiJKGjTbpvRZ5RrMTQoyTuAjrozA14FN");
var file = sigFolder.getFilesByName(sign);
var image = file.getId();
body.appendImage(image);
This next function gives the user the prompt and applies the correct template.
function chooseRow(){
var ui = SpreadsheetApp.getUi(); // Same variations.
var result = ui.prompt('Please enter the Tag number of the row you wish to print.', ui.ButtonSet.OK_CANCEL);
var button = result.getSelectedButton();
response = result.getResponseText();
if (button == ui.Button.OK) {
// User clicked "OK".
ui.alert('Your tag number is' + response + '.');
} else if (button == ui.Button.CANCEL) {
// User clicked X in the title bar.
ui.alert('You closed the dialog.');
return 'the end';
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var dataRange = sheet.getDataRange();
var values = dataRange.getValues();
var category = sheet.getRange(2, 4, 11, 1).getValues();
var templateId = {};
for(var i = 0; i < values.length; i++){
for(var j = 0; j < values[i].length; j++){
if(values[i][j] == response && category[i - 1][0] == "Instrument"){
templateId = "1cx2-6ju-o7DaRPnbuYxxdvVVFeGQzpTXaXV3wMuRpqo";
chooseRowMethod(templateId);
return "";
} else if(values[i][j] == response && category[i][0] == "Motor" || values[i][j] == response && category[i][0] == "Valve"){
templateId = "1sYx_JcoDHY-pzjEDlxMMa3dtdzOOE8CyyLGQk8WHg7s";
chooseRowMethod(templateId);
return "";
}
}
}
}
The expected result is a substring of the file path that can be used to retrieve an image that can be appended to the body of a document.
Here is a link to the spreadsheet.
I did several changes to your code, including the edit proposed by Cooper. It's retrieving the substring and adding the image to the file successfully. I hope it works for you:
function chooseRow(){
var ui = SpreadsheetApp.getUi(); // Same variations.
var result = ui.prompt('Please enter the Tag number of the row you wish to print.', ui.ButtonSet.OK_CANCEL);
var button = result.getSelectedButton();
response = result.getResponseText();
if (button == ui.Button.OK) {
// User clicked "OK".
ui.alert('Your tag number is' + response + '.');
} else if (button == ui.Button.CANCEL) {
// User clicked X in the title bar.
ui.alert('You closed the dialog.');
return 'the end';
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var tags = sheet.getRange(2, 4, 11, 1).getValues();
var category = sheet.getRange(2, 3, 11, 1).getValues();
for(var i = 0; i < tags.length; i++){
if(tags[i][0] == response && category[i][0] == "Instrument"){
var templateId = "my_template_id";
chooseRowMethod(templateId, i);
return ""; // You don't need to return empty string, just return null
} else if(tags[i][0] == response && category[i][0] == "Motor" || tags[i][0] == response && category[i][0] == "Valve"){
var templateId = "my_template_id_bis";
chooseRowMethod(templateId, i);
return ""; // You don't need to return empty string, just return null
}
}
}
The function chooseRowMethod gets the row index chosen by the user in chooseRow so that it doesn't have to be looked for again:
function chooseRowMethod(templateId, rowNumber){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var data = sheet.getRange(2, 2, 11, 18).getValues();
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1;
var yyyy = today.getFullYear();
today = dd + '/' + mm + '/' + yyyy;
var row = data[rowNumber];
var docTitle = row[1];
var docTitleTagNumber = row[2];
var docId = DriveApp.getFileById(templateId).makeCopy().getId();
var doc = DocumentApp.openById(docId);
var body = doc.getActiveSection();
body.replaceText("%SITEID%", row[0]);
body.replaceText("%TAG%", row[1]);
// ...
body.replaceText("%SAT%", row[14]);
var signature = row[17];
var sign = signature.substring(signature.indexOf("/") + 1);
var sigFolder = DriveApp.getFolderById("my_sigfolder_id");
var files=sigFolder.getFilesByName(sign);
var n = 0;
while(files.hasNext()) {
var file=files.next();
n++;
} if(n>1) {
SpreadsheetApp.getUi().alert('There is more than one file with this name: ' + sign);
}
body.appendImage(file);
doc.saveAndClose();
var file = DriveApp.getFileById(doc.getId());
var newFolder = DriveApp.getFolderById("my_newfolder_id");
newFolder.addFile(file);
doc.setName(docTitle + " " + docTitleTagNumber + " " + today);
}