Insert a reference to another cell programatically - google-apps-script

I think this should be simple, but I have searched stackoverflow and the Spreadsheet Service documentation and cannot find a way to do it.
I have a spreadsheet with an app-script. The spreadsheet has a summary sheet and multiple data sheets. On the summary sheet, I need to reference cells on the data sheet, using formulas like:
[='DataSheet1'!C10], [='DataSheet1'!C11], [='DataSheet1'!C12]
[='DataSheet2'!C10], [='DataSheet2'!C11], [='DataSheet2'!C12]
...etc
Do I have to build these formulas programatically using string concatenation, or is there a better way?
Ideally I would like to just specify a source and destination range of the same size and have the references created automatically

Related

Copying and pasting data in Google Sheets to another column

I have a dashboard that is reporting live data based on a growing customer database, and I am currently tracking the daily process by copying and pasting the data in the column into the next on a daily basis.
I'd like to create a script that automatically copies the values from an array (B:B) for example, into another sheet OR into the next available column to the right.
You may refer to the image below for further clarity.
Sample
I saw may threads on this but they were all about copying into a different row, as opposed to a different column.
Many thanks in advance!
The getLastRow() method is used to return the position of the last row that has content.
The getLastColumn() method is used to return the position of the last column that has content.
Therefore, in order to be able to copy the data into the next available column, I suggest you try this:
function copyColumn() {
var ss = SpreadsheetApp.openById("ID_OF_THE_SPREADSHEET");
var sheetFrom = ss.getSheetByName("SHEET_FROM");
var sheetTo = ss.getSheetByName("SHEET_TO");
var values = sheetFrom.getRange(NO_OF_THE_ROW_WHERE_DATA_STARTS, 3, sheetFrom.getLastRow(), 1).getValues();
sheetTo.getRange(NO_OF_THE_ROW_WHERE_DATA_STARTS,sheetTo.getLastColumn()+1,values.length,1).setValues(values);
}
The above script localizes all the data that needs to be copied by using the getRange() method and is copied by using getValues().
NO_OF_THE_ROW_WHERE_DATA_STARTS is the value representing the number of the row where your data starts (in your case the row of No of LP - Secured);
3 is the value representing the C column (where the data you want to be copied is located);
sheetFrom.getLastRow() is the value representing the end of the data you want to be copied;
1 is the value representing the number of columns that need to be copied.
Afterwards, the getRange() method is used again in order to be able to identify where the data needs to be pasted and setValues() in order to actually paste it.
Note: The above script works for different spreadsheets and/or different sheets OR for sheets in the same spreadsheet. If you want to use it for the latter case, you just have to put the name of your sheet instead of SHEET_FROM and SHEET_TO.
Moreover, I suggest you check the following links since they might be of help:
Sheet Class Apps Script - getRange();
Range Class Apps Script - getValues();
Range Class Apps Script - setValues();
Sheet Class Apps Script - getLastColumn();
Sheet Class Apps Script - getLastRow();

Update google "master" spreadsheet when other sheets are updated

I have multiple Google spreadsheets with booking data such as booking number, client name, email, booking date etc. The order of these columns is not the same in all sheets.
I would like to update all data from all my "source" sheets in one "master" spreadsheet. Meaning as soon as a new row is added or an existing row is updated, the data will be synced to the master spreadsheet
What would be the best way to achieve that? Javascript or is there some existing Google Sheets addon?
Example sheet 1: Fast boat bookings
Example sheet 2: Airport transfer bookings
Master sheet
Thanks so much to everyone looking into this!
Most people recommend to use "importrange", but I don't think this works for my use case.
I am also aware that it could be achieved by Zapier, but it would become to costly to pay for so many zaps. I believe there is another solution.
I do not have any code yet to start with :-/
I expect the data in the master sheet to be sorted by submission date and time like this:
The general procedure for using formulas is
Use IMPORTRANGE to get the data from the source spreadsheets into the master spreadsheet
Use array notation to put the imported data together
NOTES:
If you are new to using IMPORTRANGE, arrays in Google Sheets and complex formulas, use one sheet for each IMPORTRANGE, and delete the unused columns to save cells because the Google Sheets 5 million cell limit
If you prefer to use scripts, you should get the spreadsheets keys, or URLs then you could use SpreadsheetApp.openById(id) or SpreadsheetApp.openByUrl(url) to open the spreadsheets. Then you could use getValues() / setValues() to read / write the values from source spreadsheets to the master spreadsheet.
References
Using arrays in Google Sheets
Extending Google Sheets with Google Apps Script
Related
Is it possible to do ImportRange in Google Apps Script?
IMPORTRANGE to import multiple Google Sheets into one vertical column?
As a workaround for Apps Script triggers not being fired by automatic sheet updates, you need to use IMPORTRANGE to import your data into a dummy sheet. IMPORTRANGE will detect also through automatic sheet update and simultaneously it is able to fire an onEdit trigger.
Do the following:
Delete all empty rows in MASTER spreadsheet
Create a dummy spreadsheet and import into it the contents of MASTER spreadsheetwith a formula:
From the dummy sheet, open the script editor and insert the following code:
function changed(e) {
var masterSheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperty('startRow', 5);
}
var startRow=PropertiesService.getScriptProperties().getProperty('startRow');
var lastRow=masterSheet.getLastRow();
var numRows=lastRow-startRow+1;
var startCol=1;
var numCols=6;
var values=masterSheet.getRange(startRow,startCol,numRows,numCols).getValues();
var FBsheet=SpreadsheetApp.openById('1SzBx5Q9rrlcLGSqD8y5eFE5TX304LfZ7D9mxxrHhfKw').getSheetByName('Sheet1');
var ATsheet=SpreadsheetApp.openById('1IRD8wT5Kmx7h_xP807f4ibWRn8g98RjA-dJXxADXAl0').getSheetByName('Sheet1');
FBsheet.getRange(FBsheet.getLastRow()+1,startCol, numRows, numCols).setValues(values);
var ATlastRow=ATsheet.getLastRow();
for(var i=0;i<numRows;i++){
Logger.log(values[i][1]);
ATsheet.getRange(ATlastRow+1+i,1, 1, 1).setValue(values[i][1]);
ATsheet.getRange(ATlastRow+1+i,2, 1, 1).setValue(values[i][0]);
ATsheet.getRange(ATlastRow+1+i,3, 1, 1).setValue(values[i][3]);
ATsheet.getRange(ATlastRow+1+i,4, 1, 1).setValue(values[i][2]);
ATsheet.getRange(ATlastRow+1+i,5, 1, 1).setValue(values[i][5]);
ATsheet.getRange(ATlastRow+1+i,6, 1, 1).setValue(values[i][4]);
}
PropertiesService.getScriptProperties().setProperty('startRow', lastRow+1);
}
Attach to the script an onEdit trigger
Run the script once manually, it is normal that it will throw you an error
Now the script will run automatically each time data update takes place in MASTER spreadsheet.
Make sure you change all spreadsheetIDs and sheet names with your
values.

Hard link cells in script editor for Google Spreadsheet

When in Google Spreadsheet, you have formula's referencing cells to make for example a simple sum, Spreadsheets will automatically update the references, should the cells be moved. For example if the cells where cut and pasted to a different location, or rows/columns where added somewhere.
I've got this Spreadsheet where I refresh some data in using REST API's in the Spreadsheet script editor. This one runs every 5 minutes or so. However if the cells in which the data needs to be inserted, move around, my script breaks. So I have a list of constants with all kinds of cell names, for example:
/* --- EXCHANGE RATES --- */
var CELL_BTC_EUR = "B3";
var CELL_ETH_EUR = "B4";
var CELL_BNK_EUR = "B5";
But I need to update these every time I move something to optimize the spreadsheet. Is there a way to hard link it to a specific cell so that they automatically update similar to in cell formula's? Maybe not with these constant but with lines like:
sheet.getRange(CELL_BTC_EUR).setValue(btceur.last);
Potential solution
I make a seperate sheet with all my "dynamic" data which is refreshed via Spreadsheet script. In my main sheet, I can reference those cells. Thus if in my mainsheet things start moving, the reference to my other sheet stay the same. I can then hide/protect the Script Sheet.
I'm still gonna make a small table in my mainsheet with my currency exchange rates, just to get an overview of everything. But my references would not break anymore everytime I insert a new coin or something.
(better solutions are welcome. :) )

Google spreadhseet EVAL function

I have a google spreadsheet with different sheets, each one representing a different week.
For example:
1/12 - 1/16
1/19 - 1/23
I want to do a chart based on the content of those sheets. Is there any way I can make a formula and extract the name of the sheet from a content of a cell?
For example something like "=EVAL(A1)!$B$4", then I would have the content from "1/12 - 1/16"!$B$4 instead of having to go through each one of the weeks of the year manually.
Thanks for the help!
There’s no need to use AppScript, INDIRECT is enough to read a sheet name from a cell:
=INDIRECT(A1 & "!$B$4")
However, it looks like Andy’s answer is the way to go if you want to get the sheet name from its index rather than from a cell.
It'd be best to use AppScript. In Tools -> Script Editor make a new AppScript script:
function getSheetName(i) {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheets()
return s[i].getName();
}
With that in your script, you can then use the custom function =getSheetName(<SHEETNUMBER>) and it will retrieve the sheet name based what sheet number it is (starting from 0). From there, just incorporate it into your formulas. You may need to use INDIRECT.
Example: =INDIRECT(getSheetName(1)&"!A1") to get cell A1 in the second sheet.

Workaround for not losing cell's reference because of user doing sorting, while script checks cells value

I have been struggling with the following situation for almost the whole last week and it would be awesome if someone could give me some hint.
The situation:
1. Script finds a particular value in, lets say, 'Sheet1', and gets the row number of the cell containing this value.
2. Since script has found this value, it executes a bunch of actions like creating new spreadsheet and copying numerous 'Sheet1' from dozen other spreadsheets to this newly created spreadsheet, and comparing/ analyzing data.
The problem.
- While script is doing a bunch of other actions, user is able to rearrange cells by, for example, sorting A to Z, which changes the address of previously found cell.
Here is the code that I used in order to verify this:
function WhatHappensIfUserSorts () {
var ss = SpreadsheetApp.getActive();
var sh = ss.getActiveSheet();
var rng = sh.getRange("B17"); //Lets say that script finds this cell according to some rules
Utilities.sleep(10000);
rng.setValue("Test Value");
}
Question:
Might there be any workaround for this?
My current ideas.
1. I was thinking about hiding the filter row in the beginning of the script, but this doesn't help a lot, because users can insert new row in the which will change the addresses of the rows below.
The background.
I am trying to create two way synchronization, meaning, each project member has his/ her own spreadsheet with 'Project X', 'Project Y' etc. sheets and no matter who updates their project sheets, all other users that work on the same project get these updates in their project sheets. These updates that have to be tracked are not just the cell values, these are cell notes as well. And this is the reason why script has to do the bunch of other actions, since CopyTo method does not work between spreadsheets.
During my research I found sheetSpider project, but it seems somewhat different and too complicated from what I need.
A simple suggestion would be to give each row a unique identifier so that you could use it to evaluate the target range again before you write back to the sheet.
get target row's unique ID --> do work --> locate target rows ID and use to determine write range --> write back to sheet.
Alternatively, during the operation you could delete the target row and then use appendRow() to drop the updated version back in.
A third and final suggestion might be to temporarily suspend the permissions for the sheet. See: https://developers.google.com/apps-script/reference/spreadsheet/page-protection#setProtected