I have a spreadsheet with two different tabs in it. When I pass the link of the second tab, the below code always brings the content of the first tab in the sheet. New to appscript programming, any leads would be appreciated!
const currentSheetName = sheet.getSheetName();
if (currentSheetName == "AAA")
{
var sheetData = sheet.getRange('A1:A50').getValues();
for(var input=1;input<sheetData.length;input++)
{
var newURL = sheetData[input][0];
var cellrow = input+1;
if (newURL != "")
{
try{
var url = sheet.getRange(cellrow,1).getRichTextValue().getLinkUrl();
if (url != "")
{
var dataSheet = SpreadsheetApp.openByUrl(url);
}
else{
var dataSheet = SpreadsheetApp.openByUrl(newURL);
}
var job = dataSheet.getRange('M9').getValue();
}
}
}
openByUrl() returns a Spreadsheet, not a Sheet. You can use getSheetByName() or similar to get the actual sheet.
Structure of the Spreadsheet service
In general the structure of the data in the Apps Script Spreadsheet service is:
SpreadsheetApp > Spreadsheet > Sheet > Range > Data
Which is like:
Service > File > Sheet > Selection > Data
Hence the regular snippet you see at the beginning of many scripts:
ss = SpreadsheetApp.openById("<ID>")
sh = ss.getSheetByName("<SHEET NAME>")
rng = sh.getRange("<RANGE>")
data = rng.getValues()
Though as you have found, calling getRange on a Spreadsheet object does actually return a range. It will usually default to the first sheet in the spreadsheet. Though it is advisable to always explicitly assign the sheet, even if the spreadsheet only contains one sheet.
References
Services and methods of:
SpreadsheetApp service
spreadsheet object
sheet object
range object
Related
I have a Spreadsheet with a DASHBOARD + multiple (300+) sheets (within the same spreadsheet). Within the DASHBOARD I have a range column with the names of all sheets.
I'd like to automatically hyperlink all cells to sheet with corresponding name.
Example:
Try this:
function convertToLinks() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("DASHBOARD");
var range = sh.getRange("A11:A15");
var data = range.getValues();
var formulaArr = [];
data.forEach(sheet => {
var targetSheet = ss.getSheetByName(sheet[0]);
if(targetSheet){
var url = ss.getUrl() + '#gid=' + targetSheet.getSheetId();
formulaArr.push(['=HYPERLINK("'+ url +'","'+ sheet[0] +'")'])
}else{
formulaArr.push([sheet[0]]);
}
})
range.setValues(formulaArr);
}
This script above will convert cells A11:A15 to hyperlinks of the corresponding sheets.
Example:
Before:
After:
References:
Range.setValues()
Sheet.getSheetId()
Spreadsheet.getSheetByName()
You do not need hyperlinks to quickly jump to another sheet. Instead, use the name box. It is located in the formula bar to the left of the ƒ𝑥 symbol.
Click the name box and type part of a sheet name to quickly locate that sheet, then press Enter to go to the sheet.
Try this script, but also add search for the cell you need to go to (this can be done by a formula in column C) or filter based on some more info ...
function onEdit(event){
var sh = event.source.getActiveSheet();
var cel = event.source.getActiveRange();
if (sh.getName()=='DASHBOARD' && cel.getColumn()==2 && cel.getRow()>1 && cel.getValue()){
try {
cel.setValue(!cel.getValue())
// add the right destination in the targeted sheet ...
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(cel.offset(0,-1).getValue()).activate()
}
catch(err){
}
}
}
Copies of a master Google Form are emailed to groups. When a member of each group completes the form, the response is sent to a sheet in a Google Spreadsheet. If there are 10 groups, there would be 10 sheets in the spreadsheet.
The name of each sheet would default to Form Responses 1, Form Responses 2, Form Responses 3... etc.
How to change the Form Response sheet name to the name of the group.
Here is what I have attempted.
var form = FormApp.openById(copyForm.getId());
var formLink = form.getPublishedUrl();
var masterSpreadsheet = SpreadsheetApp.openById("ID");
form.setDestination(FormApp.DestinationType.SPREADSHEET, masterSpreadsheet.getId());
var sheets = masterSpreadsheet.getSheets();
for(var i = 0; i < sheets.length; i++) {
if(sheets[i].getFormUrl() == formLink) {
sheets[i].setName("Group Name");
}
}
It's renaming the sheet before the newly added sheet in the spreadsheet.
Thanks in advance.
One broad way is to create a table of group names and spreadsheets URL then use it to rename the sheet.
One way to implement the above, could be to use an on form submit trigger to rename the sheet: if the sheet has the default name pattern, rename the sheet accordingly.
var table = [
['Group A', 'url1'],
['Group B', 'url2']
]
function respondToOnFormSubmit(e){
var sheet = e.range.getSheet();
var name = sheet.getName();
if(/^Form Responses/.test(name)){
var url = sheet.getFormUrl();
var newName = table.filter((row) => return row[1] === url;)
if(newName.length > 0){
sheet.setName(newName[0]);
}
}
Related
Different Google Form Urls (How to find the linked "Form Responses" sheet) in a large Spreadsheet?
Here's how I worked around the issue:
//After your current setDestination line below:
form.setDestination(FormApp.DestinationType.SPREADSHEET, masterSpreadsheet.getId());
//insert a new sheet which will be at index [0]. This forces the sheet linked to the form created first at index [1].
// rename the sheet at index [1] -- your form response sheet
// delete the newly inserted sheet at index [0]
You may need to call SpreadsheetApp.flush() to ensure the list of spreadsheets returned by getSheets is complete. There might also be a more straightforward way by testing the names of spreadsheets, or assuming index 0 is the spreadsheet you want to rename.
var form = FormApp.openById(copyForm.getId());
var formLink = form.getPublishedUrl();
var masterSpreadsheet = SpreadsheetApp.openById("ID");
form.setDestination(FormApp.DestinationType.SPREADSHEET, masterSpreadsheet.getId());
// Flush changes
SpreadsheetApp.flush();
var sheets = masterSpreadsheet.getSheets();
for(var i = 0; i < sheets.length; i++) {
if(sheets[i].getFormUrl() == formLink) {
sheets[i].setName("Group Name");
}
}
Having issues getting the following to work.
The intent was on edit to push information from the specific cell or cells of active sheet to specific cells on a separate worksheet.
Note: I am new to google sheets
function onEdit(e) {
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Working");
var cell = source .getActiveCell();
if (cell.getRow() == 9 && cell.getColumn() == 2) {
var target = DriveApp.getFileById("1biaIVlafaNQTHjtR8ctASCpDmC2O1wwfJfAUCmzIztI")
.getSheetByName("Master_Sheet");
target.getRange("A1").setValue(cell.getValue());
}
}
The reason it does not work is because you are using onEdit(). This is a simple trigger that will fire off whenever you edit the sheet. Since simple triggers cannot perform operations that require authorization you are limited to working only in the Spreadsheet and cannot access any other files.
Read up on restrictions here
I am now able to push information to the target sheet using the following code.
function myFunction() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
var sourceData = sourceSheet.getRange("A3:C3").getValues();
sourceData.splice(0,1); // Remove header
var targetSS = SpreadsheetApp.openById("1pyJzZ86WDh2FNXFufUAt2SkAUod32i7AzvG0EKmnvEU").getSheetByName("Destination");
var targetRangeTop = targetSS.getLastRow(); // Get # rows currently in target
targetSS.getRange(targetRangeTop+1,1,sourceData.length,sourceData[0].length).setValues(sourceData);
};
I'm opting for batch update of row colors using google apps script. However I cannot go for the usual range function, as the rows to be colored are not consecutive. So I thought, a1 notation would be helpful but unfortunately it looks like I can only pass one range of a1 notation and not multiple:
var a1Notations="A1:C1,A3:C3,A10,C10";
sheet.getRange(a1Notations).setBackground("red");
But I'm getting "Range not found" error.
Any ideas how can I make this work?
Thanks!
To multi-select a number of ranges and change the color:
var sheet = SpreadsheetApp.getActiveSheet();
var rangeList = sheet.getRangeList(['A1:C1','A3:C3','A10','C10']);
sheet.setActiveRangeList(rangeList).setBackground("red");
If you want to type a list in a dialog box:
function promptRangesList() {
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Comma-separated ranges list', 'E.g.: A1:C1,A3:C3,A10,C10 or C3,C7,C17,C56', ui.ButtonSet.OK_CANCEL);
Logger.log(response.getSelectedButton());
// Process the user's response.
if (response.getSelectedButton() == ui.Button.OK) {
if (response.getResponseText()!=='') {
var list = response.getResponseText().split(',');
Logger.log(list);
var rangeslist = SpreadsheetApp.getActiveSheet().getRangeList(list).setBackground("red");
Logger.log(rangeslist);
rangeslist.activate();
} else {
Logger.log('getResponseText empty');
}
} else if (response.getSelectedButton() == ui.Button.CANCEL) {
Logger.log('CANCELED');
} else {
Logger.log('The user clicked the close button in the dialog\'s title bar.');
}
}
Reference:
Class RangeList - Selects the list of Range instances
Class Sheet - Sets the specified list of ranges as the active ranges in the active sheet.
Prompt dialogs - A prompt is a pre-built dialog box that opens inside a Google Docs, Sheets, or Forms editor.
Put the range notations into an array, then loop through the array:
function setMultiRanges() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var a1Notations=["A1:C1","A3:C3","A10","C10"];
var i=0,
arryLngth = a1Notations.length;
for (i=0;i<arryLngth;i+=1) {
//Logger.log(a1Notations[i]);
//Logger.log(typeof a1Notations[i]);
sh.getRange(a1Notations[i]).setBackground("red");
};
};
Set each range independently
sheet.getRange("A1:C1").setBackground("red");
sheet.getRange("A3:C3").setBackground("red");
sheet.getRange("A10:C10").setBackground("red");
According to the doc of Google Sheets' API V4 the way to select multiple ranges is to pass an array of ranges.
var ranges = ["'EVERYTHING'!A:A", "'EVERYTHING'!Z:Z"];
// I use Node.js, so my call to the API looks like this:
service.spreadsheets.values.batchGet({
spreadsheetId: spreadsheetId,
ranges: ranges
}, function(err, result) { ...
Then what you get is an array of data, [{first range}, {second range}, {etc...}]
I have a Google Sheet which is storing the answers to my form and in theory should bucket the responses by the value selected from a drop down for my form labeled "Location of Change". So far the script accurately creates a new sheet from each response and adds a row with that responses information to newly created sheet, but it creates a new sheet for every response rather then add add responses that contain the same value selected from "Location of Change" to the same sheet.
I assume this is happening because there is a disconnect between the destSheet variable that looks for the values of the "Location of Change" and the getSheet() function, but I could be wrong.
Here is my code:
function onSubmit(e) {
//Open Marketing - Discoveries and Changes - v1
var sheet = e.range.getSheet();
//Return Spreadsheet that contains this sheet
var ss = sheet.getParent();
//Open Marketing - Discoveries and Changes - v1
var form = FormApp.openByUrl(ss.getFormUrl());
//Destination sheet based on "Location of Change"
var destSheet = getSheet(ss, e.namedValues["Location of Change"]);
//Store response in destination sheet
destSheet.appendRow(e.values);
function getSheet( spreadsheet, sheetName, headings) {
spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(sheetName);
if (sheet == null) {
sheet = spreadsheet.insertSheet(sheetName);
if (headings && headings.constructor === Array) {
sheet.getRange(1,1,1, headings.length).setValues([headings]);
}
}
return sheet;
}
}
I think the problem is that e.namedValues stores all values as arrays even if there is only one value. So e.namedValues["Location of Change"] should be
e.namedValues["Location of Change"][0]