Google Spreadsheet: loop through sheets stop working - google-apps-script

i've a function called when opening my spreadsheet that aim to loop trought all sheets, activate them and set cursor to the last modified cell (saved by another function) and, a the last re-select the last used sheet (saved as before by another function).
It worked fine for years, but suddenly stopped working.
Here is my code:
function onOpen()
{
var timer = 2000;
var proprieta = PropertiesService.getScriptProperties();
var lastSheet = proprieta.getProperty("ultimo");
var lastModifiedCell = proprieta.getProperty(lastSheet);
var applicazione = SpreadsheetApp.getActive();
var fogli = applicazione.getSheets();
var ui = SpreadsheetApp.getUi();
for (var i=0; i < fogli.length; i++)
{
var attuale = fogli[i].getName();
var ultimorange = proprieta.getProperty(attuale);
applicazione.getSheetByName(attuale).getRange(ultimorange).activate();
//ui.alert(attuale);
//ui.alert(ultimorange);
Utilities.sleep(timer);
}
applicazione.getSheetByName(lastSheet).getRange(lastModifiedCell).activate();
}
Doesn't return any error but the for loop is not selecting anymore sheet and range given.
If i enable the ui.alert the sheet name and range are displayed correctly.
The last selection ath the end, works correctly...i have no idea why it happens...
Is there anyone who can help me figure out what's wrong?
Thanks to anyone who will answer!!!

I was able to replicate the issue. To prevent this from happening, you can use SpreadsheetApp.flush()
Your code:
function onOpen()
{
var timer = 2000;
var proprieta = PropertiesService.getScriptProperties();
var lastSheet = proprieta.getProperty("ultimo");
var lastModifiedCell = proprieta.getProperty(lastSheet);
var applicazione = SpreadsheetApp.getActive();
var fogli = applicazione.getSheets();
var ui = SpreadsheetApp.getUi();
for (var i=0; i < fogli.length; i++)
{
var attuale = fogli[i].getName();
var ultimorange = proprieta.getProperty(attuale);
var range = applicazione.getSheetByName(attuale).getRange(ultimorange).activate();
SpreadsheetApp.flush();
Utilities.sleep(timer);
}
applicazione.getSheetByName(lastSheet).getRange(lastModifiedCell).activate();
ui.alert("Activation Done");
}

I'm new but i found something recently (i come from excel scripts) :
getting a "range" and getting it's a1Notation are totally different.
Maybe your "ultimorange" (from "attuale") is a range and NOT the notation of the range. It would make getRange(ultimorange) not working.

Related

Google Sheets to link to Google Team Calendar using Script Editor

Hi I've been trying to experiment with google's script editor and i think that I've gotten the code right but it wont seem to work. I used the code they made in google's tutorial video with edits but it cant seem to create an event. On the executions page it says completed but no new event is showing up.
Anyway i've attached screen shots of the sheet as well as the code. Hope y'all can help thanks!
function scheduleMeetings() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange('H6').getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
var tasks = spreadsheet.getRange("G10:H100").getValue();
for (x=0; x<tasks.length; x++) {
var schedules = tasks[x];
var date = schedules[0];
var task = schedules[1];
eventCal.createAllDayEvent(task, date);
}
}
Try this:
function scheduleMeetings() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange('H6').getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
var tasks = spreadsheet.getRange("G10:H100").getValues();//you had getValue()
for (var x=0;x<tasks.length;x++) {
var schedules = tasks[x];//Select a row
var date = schedules[0];//column G
var task = schedules[1];//column H
//you may need to add var date=new Date(schedules[0]);
eventCal.createAllDayEvent(task, date);
}
}

How to copy active text from google docs to spreadsheet with menu item/option

I'm fairly new to google apps and I know that similar questions have been asked but they only adress similar problems. I hope you can help me.
I want to copy an active text from a google docs to a given spreadsheet via a button. I've done similar for spreadsheet to spreadsheet but I'm failing on docs to spreadsheet.
function onOpen(e) {
DocumentApp.getUi()
.createMenu('Copy active Range.')
.addItem('Copy Button', 'Copy')
.addToUi();
}
function Copy() {
var ss = DocumentApp.getActiveDocument();
var selection = ss.getSelection();
var tss = SpreadsheetApp.openById("xxx");
var ts = tss.getSheetByName("name");
trange = ts.getRange("B6:B6")
selection.copyto(trange);
}
Thanks in advance to everyone investing time thinking about my problem.
You can try this code
var SPREADSHEET_ID = "YYYY"; // = assign your spreadsheet id to this variable
var SHEET_NAME = "XXXXX"; // = assign your sheet name to this variable
function onOpen(e) {
DocumentApp.getUi()
.createMenu('Copy active Range.')
.addItem('Copy Button', 'Copy')
.addToUi();
}
function Copy() {
var ss = DocumentApp.getActiveDocument();
var selection = ss.getSelection();
var result = "";
//Proceed only if something is selected, otherwise selection will be null
if (selection) {
var elements = selection.getRangeElements();
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
// Only modify elements that can be edited as text; skip images and other non-text elements.
if (element.getElement().editAsText) {
result += element.getElement().asText().getText();
}
}
var tss = SpreadsheetApp.openById(SPREADSHEET_ID);
var ts = tss.getSheetByName(SHEET_NAME);
trange = ts.getRange(2, 6); //I think, you can use B6 also
trange.setValue(result);
}
}
This is not a tested code let me know if any error pops ups. I'll happy to debug together.
If it works, accepts/upvote this answer so that other people can also get help from this.

google sheets script conditionally move row to another spreadsheet

I am new to this and I am having some trouble trying to figure this out. I have a spreadsheet that collects data from a google form. I am trying to find a way to move that data based on a column answer to a different google sheet. (Not a sheet in the same document but a different document all together). It seems like there is some information about moving to a different tab in the same document, but not a different document.
I will first say that I tried just an IMPORTRANGE function, but that only mirrors the data, and does not let you update or change cells.
Here is what I have been able to piece together so far, but I may be way off.
I have a trigger that would run every hour.
function myFunction() {
var ss = SpreadsheetApp.openById('1U0I9SkbGkHgm-vRkwf2Ppc_yxlqrVlg2t8yKRy3sYuI');
var sheetOrg = ss.getSheetByName("Form Responses 1");
var value1ToWatch = "ANDERSON";
var value2ToWatch = "BARNES";
var sheetNameToMoveTheRowTo = "Sheet1"; //sheet has same name for each target openByID(" *url key* ")
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms");
sheet1in = ts1.getSheetByName("Sheet1");
var ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ");
sheet1in = ts2.getSheetByName("Sheet1");
arr = [],
values = sheetOrg.getDataRange().getValues(),
i = values.length;
while (--i) {
if (value1ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet1in.getRange(sheet1in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
if (value2ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet2in.getRange(sheet2in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
}
}
The sheet google forms dumps the information into is "Form Responses 1".
Column B is the cells I want to get the values from. (There are a total of 9 different values that it can be like "ANDERSON", "BARNES", "SMITH", etc).
For sheetNameToMoveTheRowTo is "Sheet1" - that may be confusing and I may need to change that, but for example
ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms") the sheet name that I want the information moved to is "Sheet1".
ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ") the sheet name is also "Sheet1" but in a different document.
I think if I were able to get the "ANDERSON" one to work, then I can just add additional variables for each possible response, and just copy and paste additional "IF" statements, just changing the valueToWatch and targetSheet values. <= if that is not correct please let me know
I have tried to both debug, and run the script above but nothing happens. There are no errors reported on the debug, but it is not moving any information over.
Any idea what I am doing wrong?
// UPDATE I got this to work. I have updated the code listed with what worked for me.
I think that copyTo() method will not work like you mentioned, it operates on same SpreadSheet. I'm sending you example with looping on source sheet data and then setting the target sheet values with it.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var allrange = ss.getActiveRange();
var range = sheet.getRange("A1:A10");
var values = range.getValues();
var allvals = [];
for(var i = 0; i < values.length; i++) {
allvals.push( values[i] ) ;
}
var dataLength = allvals.length;
// alert data
var ui = SpreadsheetApp.getUi();
// ui.alert( JSON.stringify(allvals) )
// copy to new Google SpreadSheet
var newSheet = SpreadsheetApp.openById('1F79XkNPWm2cCWlB2JP3K4tAYRESKUgtHK4Pn2vbJEiI').getSheets()[0];
var tmp = "A1:A" + dataLength ;
var newRange = newSheet.getRange( tmp );
newRange.setValues( allvals );
}
Here's a simple example of moving data from one spreadsheet to another.
function movingDataToSS(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var dsh=dss.getSheetByName('Sheet1');
var drg=dsh.getRange(1,1,rg.getHeight(),rg.getWidth()).setValues(vA);
}
If you interested in placing some conditions on your output by only getting output from odd rows and even columns.
function movingDataOddRowsAndEvenCols(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var h=rg.getHeight();
var w=rg.getWidth();
var dsh=dss.getSheetByName('Sheet1');
for(var i=0;i<h;i++){
var out=[];
if(i%2==0){
for(var j=0;j<w;j++){
if(j%2==1){
out.push(vA[i][j]);
}
}
dsh.appendRow(out);
}
}
}

Pasting values only to another column automatically based on time passed

I am currently working on setting up a Google Doc to track live web data using ImportXML and want to copy those figures to other columns after specific time intervals. I am tracking the date info is entered and then for every 15 days automatically copying this info to another column for multiple accounts. Here is my code so far which is working on row 1, but now that I have it working for one cell I want to do this for the whole column individually:
function moveValuesOnly() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var currentValue = sheet.getRange("B4").getValue();
if (currentValue == (15)) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange("H4");
var copyRange = ss.getRange("H4");
var l = ss.getDataRange().getValues().length;
var pasteRange = ss.getRange("R4");
pasteRange.setValues(copyRange.getValues());
}}
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var currentValue = sheet.getRange("B5").getValue();
if (currentValue == (30)) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange("H4");
var copyRange = ss.getRange("H4");
var l = ss.getDataRange().getValues().length;
var pasteRange = ss.getRange("T5");
pasteRange.setValues(copyRange.getValues());
}
Is there any way to have it evaluate line by line and not all at once? I am guessing I should not be using range, but I have no idea how else to do this. Any help will be very much appreciated!! If I can clarify anything let me know.
THANK YOU!
How are you invoking this script ? As a formula in the spreadsheet or from the script editor ?
If you're using it as a formula, you can read the range directly.
If you're invoking it from the script editor, you can make small changes to your script to make it work across a range larger than a cell. See the code below
function moveValuesOnly() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var range= sheet.getRange("B4:R20");
var currentValue = range.getValues(); // Change 20 to whatever you want
var COL_B = 0; // relative to col B
var COL_H = 6;
var COL_R = 16;
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (15)) {
// Copy value in H4, H5 etc to R4, R5 etc.
currentValue[i][COL_R] = currentValue[i][COL_H];
}
range.setValues(currentValue);
}
I haven't tested it but if you find any minor errors feel free to fix it:)

Change copyDown() Script to operate on just one Sheet

In Google Sheets I have a sheet with Form Responses, and to the right of the form columns I have columns with formulas that use form data for functions.
At the start I had the formulas extended down the rows so they worked on new form submissions, but found that new form submissions would clear the row out :(.
Instead of manually extending formulas down after each submission I installed Andrew Stillman's copyDown() script; what it does is copies down the formulas after scripts are submitted.
Now the problem I'm having is that the script works when run manually, but when I set to trigger on form submits it copies the said formula on that sheet and on all other sheets in the spreadsheet. I Do Not Want that side-effect, as it messes the whole spreadsheet up. :((
What I thought to do is edit script so it only works on the one Form Response sheet, not all sheets. But I don't know how to do that.
The name of the sheet I want it to run on is "Requests", and the gid=8.
How do I edit this script to only work for that one sheet?
To get code to run on just a particular sheet use the .getSheetByName() method. For example:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var reqSh = ss.getSheetByName('Requests');
There is another way that might be easier. You could try keeping one sheet purely for form submissions and use an arrayformula in a second sheet to copy any values from the first sheet to the same range in the second.
=ARRAYFORMULA('Requests'!A1:H) would copy columns A to H.
I had the same problem as you and this was the solution. I placed my formulas in the second sheet in the columns to the right of the range and copied them down in the normal way. The formulas referred to the copied range in the second sheet. It worked a treat.
I didn't come up with the idea myself - I'm sure it was suggested by someone on the Google spreadsheet forum. I should give you a link to the post but I just looked and I can't find it.
In your code you have (comments in code)
var sheets = ss.getSheets() [8]; // you choose sheet [8]
var cellAddresses = new Object();
for (var i=0; i<sheets.length; i++) { // but you enter a for loop that adresses every sheet in turn...
var range = sheets[i].getDataRange();
You should simply suppress this loop and use only the sheet number you want to be proceeded ...
The simplest way could be to do it like this :
var i = 8
var sheets = ss.getSheets() [i];
var cellAddresses = new Object();
var range = sheets[i].getDataRange();
...
and at the end of the loop delete the } that fitted the for loop
EDIT : the new code should be like this :
function copydown() {
setCopyDownUid();
setCopyDownSid();
logCopyDown();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets() [8];
var cellAddresses = new Object();
var i=8
// for (var i=0; i<sheets.length; i++) {
var range = sheets[i].getDataRange();
var lastRow = range.getLastRow();
var values = range.getValues();
for (var j=0; j<values.length; j++) {
for (var k=0; k<values[j].length; k++) {
var test = values[j][k].toString();
var start = test.indexOf("copydown");
if (start == 0) {
start = start+10;
var end = test.length-2;
var length = end-start;
var value = test.substr(start, length);
var col = k+1;
var nextRow = j+2;
var numRows = lastRow-(nextRow-1);
if (numRows>0) {
var destRange = sheets[i].getRange(nextRow, col, numRows, 1);
destRange.clear();
var newLastRow = sheets[i].getDataRange().getLastRow();
var newNumRows = newLastRow-(nextRow-1);
var newDestRange = sheets[i].getRange(nextRow, col, newNumRows, 1);
var cell = sheets[i].getRange(nextRow-1, col);
cell.setFormula(value);
cell.copyTo(newDestRange);
}
var cellAddress = cell.getA1Notation();
cellAddresses[cellAddress] = test;
}
}
}
Utilities.sleep(500);
resetCellValues(cellAddresses, sheets[i]);
}
//}