Declaring a variable stops the function in apps script [closed] - google-apps-script

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm creating a projects database using google sheets and Apps Script.
I have developed the code below to add a new record page (sheet) every time a new record/project is added to the projects list sheet.
The strange thing is that the code works well but when I declare the variable text in line 11 the code doesn't work. Actually, the variable text is not even used in the code yet. it doesn't contribute to the code's logic.
Can anyone explain this to me, please?
// This module is to add a new project record page when a new project included in the Project List sheet
function addNewRecord(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = ss.getActiveSheet().getSheetName();
var sheet = e.source.getSheetByName("Template");
var row = e.range.getRow();
var col = e.range.getColumn();
var cell = e.source.getActiveSheet().getRange(row,1).getValue();
var text = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Projects List').getRange(row,1).getCell(row,1);
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets(); //creating an array or calling the existing sheets of the spreadsheet.
var sheetsNames = []; //creating an array of the existing sheets names
for (let i =0 ; i < sheets.length; i++){
sheetsNames[i] = sheets[i].getSheetName();
}
//checking the entered value contains LCE keyword and it's an actual new record
if (sheetName === 'Projects List' && col ===1){
if (cell.includes('LCE') && sheetsNames.indexOf(cell) === -1){
sheet.copyTo(ss).setName(cell);
ss.getSheetByName(cell).getRange(1,2).setValue(cell);
function getSheetUrl() {
var SS = SpreadsheetApp.getActiveSpreadsheet();
var ss = SS.getSheetByName(cell);
var url = '';
url += SS.getUrl();
url += '#gid=';
url += ss.getSheetId();
//Logger.log(url);
return url;
}
var value = SpreadsheetApp.newRichTextValue().setText(cell).setLinkUrl(getSheetUrl()).build();
//e.source.getSheetByName('Projects List').getRange(row,1).getCell(row,1).setRichTextValue(value);
//cellV.setRichTextValue(value);
}
}
//Logger.log(sheets);
}

looks like your variable "image" is a UIImageView, not a UIImage. Replace this line
var myRGBA = RGBAImage(image: image)
with this
var myRGBA = RGBAImage(image: image.image)
This is because a UIImageView holds an image. To access it you must call UIImageView.image
For future reference, you should always copy and paste code, not posting a screenshot, so that other users can find questions easier through search engines, and users trying to answer your questions can replicate your issue by copying and pasting your code into their own environment.

Related

Running a script from a particular Sheet [duplicate]

This question already has an answer here:
Script to run on specific sheet
(1 answer)
Closed 6 months ago.
I'm trying to put together a code and want the code to choose a selected sheet rather than the active sheet - the Sheet that I want the code to run from has been renamed 'Training Record':
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues()
The rest of the code is as follows and runs as intended without the change that I need:
function createTrainingDocs() {
var tempID ='1dyQIK3OCPWXDLydg-MKRhL43CACtyQQDG3VUR11PlH8'
var folderID = '1UpVdcyuP-c_PZVx8uEBRVEH7m_zBnzvb'
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues()
//console.log(data)
data.forEach((row,i)=>{
console.log(row[2]+', '+row[1]+' Training Log')
var newDocID = DriveApp.getFileById(tempID).makeCopy(row[2]+', '+row[1]+' Training Log',DriveApp.getFolderById(folderID)).getId()
var body = DocumentApp.openById(newDocID).getBody()
body.replaceText('{{Name}}',row[1]+' '+row[2])
body.replaceText('{{School Name}}',row[0])
SpreadsheetApp.getActiveSheet().getRange(i+1,4).setValue(newDocID)
})
}
Change
var data = SpreadsheetApp.getActiveSheet().getDataRange().getValues()
To
var spread = SpreadsheetApp.getActiveSpreadsheet();
var data = spread.getSheetByName("Training Record").getDataRange().getValues()

How to get access new sheet, created by adding a new form to spreadsheet?

Im quite new to this thing and never had to post a question before.
Here is the situation :
I want to copy the same form over and over to the same spreadsheet('memoSs'). (original form being 'formFileSample').
I am trying to access the sheet linked to that newly added form. (form added using .setDestination()
Unfortunately that sheet is missing from the array returned by '.getSheets'!
Even though it appears in the spreadsheet 'memoSs' (checked by opening it)
I hope it is understandable with the script below.
any chance somebody might have a way in doing so?
function updateOfMemoSs() {
var memoId = 'xxxxxxxxxxxxxxxxxxxxxxxxx'
var Interface = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Interface');
var memoSs = SpreadsheetApp.openById(memoId);
var formFileSample = DriveApp.getFileById(memoSs.getSheetByName('Sample (Source)').getFormUrl().match(/[-\w]{25,}/));
var sheetsToCopy = setInstrList(); //sets a list of names for the sheets to be created
//looks like [['xxx'],['xx'],['x']]
for(var i in sheetsToCopy){
var newFormId = formFileSample.makeCopy('memo '+sheetsToCopy[i][0]).getId();
var newForm = FormApp.openById(newFormId).setDestination(FormApp.DestinationType.SPREADSHEET, memoId);
// var memoSs = SpreadsheetApp.openById(memoId); //didnt work
var sheets = memoSs.getSheets().filter(sheet => sheet.getFormUrl()); //sets a list of linked sheets
Logger.log('formIds = ');
for(var j in sheets){
Logger.log(sheets[j].getName());
Logger.log(sheets[j].getFormUrl().match(/[-\w]{25,}/));
}//returns a list that does not include the linked sheet created earlier.(even though it appears in spreadsheet)
/* for(var j in sheets){
var sheet = sheets[j];
if(sheet.getFormUrl().match(/[-\w]{25,}/) == newFormId){
var newSheet = sheet; //therefore I never find a match for newFormId
}
}*/
}
// Logger.log('newSheet = ');
// Logger.log(newSheet.getName());
}
Thanks Cooper for considering the question.
It seems i haven't been patient enough in my research as the answer had already been posted in StackOverFlow : 'getSheets() Google Apps Script multiple calls issue'
Somehow after creating a sheet.The following should be called before calling getSheets() :
SpreadsheetApp.flush()

Script - Add/Remove Google Sheet Editors for a list

Example Document: Link
I have had a working script that would add or remove editors from a specified sheet ID for a good few months until recently it has started giving an error of:
Exception: The parameters (number[]) don't match the method signature for SpreadsheetApp.Spreadsheet.removeEditor.
Nothing has changed recently regarding the input I am providing the script so I am at a bit of a loss.
The script is as follows:
function runEmailAccess(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sEditors = ss.getSheetByName('Editors');
var sheet = SpreadsheetApp.openById("SHEETID");
var nAddEditor = sEditors.getRange('A2').getValue();
if (nAddEditor != 0){
var vAddEditor = sEditors.getRange('A3:A'+nAddEditor).getValues();
sheet.addEditors(vAddEditor);
}
var nRemoveEditor = sEditors.getRange('B2').getValue();
if (nRemoveEditor != 0){
var vRemoveEditor = sEditors.getRange('B3:B'+nRemoveEditor).getValues();
for (j=0;j<vRemoveEditor.length;j++) {
sheet.removeEditor(vRemoveEditor[j])
}
}
}
The script takes the row number of last email in the list from Row 2 then takes the emails for row 3 to that row via .getRange.
Any help regarding this would be of great help.
Thanks.
vRemoveEditor is 2D array. You're indexing only into the outer array with vRemoveEditor[j]. You need to index into both to get primitive values: vRemoveEditor[j][0]

Get the last updated CELL in Google sheets and then grab the row. GAS

So I have a google form feeding into a sheet, and from the spreadsheet I'm making google docs from a template with the answers in the spreadsheet.
The form has the ability to save mid way and come back later via a custom question asking if they want to save and comeback (this submits the form). The script on my spreadsheet activates onFormSubmit so when they quit, the template gets created with half their answers. When they eventually come back and finish it off, I want the script to know where to create the template from.
For instance, 5 more rows were added since they quit and the script creates the template from a manual change of the line 'var tactics' by changing the numbers to the row. e.g. if I was about to test another entry, I'd change the numbers to the next empty row first, then when the form is submitted, it would use that row. Not practical. It wouldn't work.
I've looked around a bit and found onEdit(e) but that doesn't work unless it's a manual entry.
My question is, is there another way other than onEdit to find the last cell UPDATED, not ADDED else it'll grab the last row in the sheet, which I don't want. If it grabs the last cell updated then it will grab the correct row to run the script for. I'll add my script to the bottom if it'll help. ID's etc. have obviously been removed.
Any ideas?
function onFormSubmit(e) {
var Sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var headers = Sheets.Spreadsheets.Values.get('myID', 'A1:U1');
var tactics = Sheets.Spreadsheets.Values.get('myID', 'A6:U6');
var templateID = "myID"
for(var i = 0; i < tactics.values.length; i++){
var Timestamp = tactics.values[i][0];
var IDCFREF = tactics.values[i][2];
var raisedby = tactics.values[i][4];
var AccMan = tactics.values[i][6];
var Contrib = tactics.values[i][7];
var Contract = tactics.values[i][8];
var CompName = tactics.values[i][9];
var ValidFrom = tactics.values[i][10];
var ValidTo = tactics.values[i][11];
var Freq = tactics.values[i][12];
var PDetailFreq = tactics.values[i][13];
var BillType = tactics.values[i][14];
var TypeOfRebate = tactics.values[i][15];
var RebateDetails = tactics.values[i][16];
var RTarget = tactics.values[i][17];
var GiveDeets = tactics.values[i][19];
var WhyGiveRebate = tactics.values[i][20];
var documentID = DriveApp.getFileById(templateID).makeCopy().getId();
DriveApp.getFileById(documentID).setName('Rebate ' + IDCFREF + ' Request');
var body = DocumentApp.openById(documentID).getBody();
var header = DocumentApp.openById(documentID).getHeader();
header.replaceText('##IDCF##', IDCFREF)
body.replaceText('##REF##', IDCFREF)
body.replaceText('##RAISED##', raisedby)
body.replaceText('##ACCMAN##', AccMan)
body.replaceText('##CONTRIB##', Contrib)
body.replaceText('##SIGNED##', Contract)
body.replaceText('##NAME##', CompName)
body.replaceText('##FROM##', ValidFrom)
body.replaceText('##TO##', ValidTo)
body.replaceText('##FREQ##', Freq)
body.replaceText('##BESPOKE##', PDetailFreq)
body.replaceText('##BILL##', BillType)
body.replaceText('##TYPE##', TypeOfRebate)
body.replaceText('##DEETS##', RebateDetails)
body.replaceText('##TARGET##', RTarget)
body.replaceText('##FULL##', GiveDeets)
body.replaceText('##ELAB##', WhyGiveRebate)
}
}
So for anyone who has the same issue, here was my solution:
function onFormSubmit(e) {
var range = e.range;
var ss = range.getSheet();
var row = range.getRowIndex();
var tactics = Sheets.Spreadsheets.Values.get('ID', "A:AQ"+row);
The way it works is just delete every row in the form responses sheet up until the last entry, and then voila. ("A:AQ"+row) gets the row index from the variable 'row' created from 'e.range' upon form submission.
It works great for me, if 3 forms were filled in and 3 lines were added to the sheet before another came back to edit his responses, the script knows what row to find the data on in the sheet, thus creating the correct template.

How to Add or Remove Rows Based on Data in Column [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I was presented with a problem where static fields were being modified next to dynamic fields in a Google Spreadsheet. The issue being sometimes the column with dynamic data would change and the static fields would no longer apply to them.
I can't think of a way to handle this except for a script, but my scripting knowledge is limited at best.
The idea is to have a sheet that uses =importrange() that would house the dynamic data. Then a second sheet would have the static data which would have rows added or removed based on whether they match the dynamic sheet.
For example:
The dynamic sheet would be called "Source" and in the first column we would have the names: Peter, Brian, Louis, Chris, Stewie
The static sheet would be called "Target" and in the first column we would have the names: Peter, Brian, Louis, Chris, Meg
The idea would be to remove the row that has "Meg" in the first column and then insert a row (or add to the bottom of the range) the value of "Stewie".
End goal is to programmatically make the static list match the dynamic list.
After piecing together how I thought the process should go I was able to throw this together. I have two functions that get called by a third one. The first function is used to grab a 2d array of whichever sheet I need. The assumption here is the arrays that I'll be comparing to each other will all be in the first column.
function grabSheetInformation(sheet) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetInfo = ss.getSheetByName(sheet);
var range = sheetInfo.getRange("A2:A").getValues();
var rangeMax = range.filter(String).length;
range = sheetInfo.getRange("A2:A" + (rangeMax + 1)).getValues();
return range;
}
The second function that I use just sorts the data after everything is said and done.
function sortTargetData() {
var sheetToSort = "Target"; // sheet name that is being sorted
var columnToSortBy = 1; // column A = 1, B = 2, etc.
var rangeToSort = "A2:R";
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetToSort);
var range = sheet.getRange(rangeToSort);
range.sort( { column : columnToSortBy, ascending: true } );
}
This is where it all comes together.
function mergeData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceInfo = grabSheetInformation("Source");
var targetInfo = grabSheetInformation("Target");
var sourceMax = sourceInfo.length;
var targetMax = targetInfo.length;
SpreadsheetApp.setActiveSheet(ss.getSheetByName("Target"));
var sheet = ss.getActiveSheet();
var array = [];
var offset = 1;
for (var i = 0; i < targetMax; i++) {
array.push(targetInfo[i][0]);
}
for (i = 0; i < sourceMax; i++) {
if(array.indexOf(sourceInfo[i][0]) == -1) {
sheet.insertRowAfter(targetMax + offset);
sheet.getRange("A" + (targetMax + offset + 1)).setValue(sourceInfo[i][0]);
offset++;
}
}
// reset variables
sourceInfo = grabSheetInformation("Source");
targetInfo = grabSheetInformation("Target");
sourceMax = sourceInfo.length;
targetMax = targetInfo.length;
sheet = ss.getActiveSheet();
array = [];
for (i = 0; i < sourceMax; i++) {
array.push(sourceInfo[i][0]);
}
for (i = targetMax -1; i >= 0; i--) {
if(array.indexOf(targetInfo[i][0]) == -1) {
sheet.deleteRow(i+2);
}
}
sortTargetData();
}
As I posted in my initial question, the purpose of the script is to allow a user to have a dynamic list that they can add static values to.
The layout of the spreadsheet would have two tabs, "Source" and "Target". The "Source" tab would have the dynamic data in the first column with a header. For my use-case it would be pulled in using "=importrange()". The "Target" tab would have the first row contain headers and be updated via the script.
If there were values in the "Source" tab that weren't in the "Target" tab then rows would be added to the end of the list on the "Target" tab with the missing values added.
If there were values in the "Target" tab that weren't in the "Source" tab then the offending rows would be deleted.
My organization has multiple spreadsheets with employee names all over the place. The benefit of this would be to have a single list of names that can be updated and spreadsheets would automatically update with the most up-to-date list.
There is also the assumption that names won't be duplicated.
Spreadsheet that I created to test this out on:
Shared View Only Spreadsheet