How to set the newly created sheet as the active sheet? Google sheets - javascript

Am having a problem that I have to run each script alone due to not being able to switch to the newly created sheet generated by the function copyWithProtections, so when the next function ClearValueAftercreatingnewsheet runs, it runs on the active sheet not the newly generated one, is there a way to to have the newly created sheet as the active one?
/* CAUTION: COPY WITH PROTECTION SHOULD BE RUNNED FIRST THEN CLEARVALUEAFTERCREATING NEW SHEET AFTER MAKING SURE THAT YOU MANUALLY CHANGED THE ACTIVE SHEET TO THE NEW SHEET WITH THE NUMBER */
//Copies with protection
function copyWithProtections(){
const sh = SpreadsheetApp.getActiveSpreadsheet();
const ss = sh.getSheetByName("Mar22");
const prot = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE)
let nSheet = ss.copyTo(sh).setName(sh.getNumSheets()-1);
let p;
for (let i in prot){
p = nSheet.getRange(prot[i].getRange().getA1Notation()).protect();
p.removeEditors(p.getEditors());
if (p.canDomainEdit()) {
p.setDomainEdit(false);
}
}
}
//Clears Values of new sheets
function ClearValueAftercreatingnewsheet() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A2:P144').activate().clear({contentsOnly: true});
spreadsheet.getRange('Z5').activate();
spreadsheet.getCurrentCell().setValue('');
spreadsheet.getRange('Z8').activate();
spreadsheet.getCurrentCell().setValue('');
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('A2:Q270').activate();
spreadsheet.getActiveRangeList().setBackground('#deeaf6');
spreadsheet.getRange('A2:R270').activate();
spreadsheet.getActiveRangeList().setBorder(true, true, true, true, true, true, '#000000', SpreadsheetApp.BorderStyle.SOLID);
};

You can set the active sheet from the sheet name.
By making your script in one single function, you can use the newly created output sheet nSheet and get it's name using getSheetName(). You can then reference it on the clear values part. Try the following code instead:
function copyAndClear() {
//Copies with protection
const sh = SpreadsheetApp.getActiveSpreadsheet();
const ss = sh.getSheetByName("Mar22");
const prot = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE)
let nSheet = ss.copyTo(sh).setName(sh.getNumSheets() - 1);
let p;
for (let i in prot) {
p = nSheet.getRange(prot[i].getRange().getA1Notation()).protect();
p.removeEditors(p.getEditors());
if (p.canDomainEdit()) {
p.setDomainEdit(false);
}
}
//Set the newly created sheet name in a variable to be used for reference
var nSheetName = nSheet.getSheetName();
//Clears Values of new sheets
var spreadsheet = sh.getSheetByName(nSheetName);
spreadsheet.getRange('A2:P144').activate().clear({contentsOnly: true});
spreadsheet.getRange('Z5').setValue('');
spreadsheet.getRange('Z8').setValue('');
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('A2:Q270').setBackground('#deeaf6');
spreadsheet.getRange('A2:R270').setBorder(true, true, true, true, true, true, '#000000', SpreadsheetApp.BorderStyle.SOLID);
};
I have also simplified your code to avoid redundancy and make the run time shorter since based on your code there's no need for the .activate() if you can just set it directly in one line.
Let me know if this works!
You can also set the active sheet by ID but the code will be much longer.
Here's the reference for setting active sheet: https://spreadsheet.dev/activate-sheet-in-google-sheets-using-google-apps-script
EDIT: I have kept the .activate() on the first line
spreadsheet.getRange('A2:P144').activate().clear({contentsOnly: true});
as for some reason if I set it directly as
spreadsheet.getRange('A2:P144').clear({contentsOnly: true});
without the .activate() it is also clearing the original sheet.

Related

Take selected text, send it over to Scryfall API, then take the link and put it in the selected text

I've been able to sort out the middle bit (the API seems to be called to just fine) along with the submenu displaying. Originally I thought that just the end part wasn't working but I'm now thinking that the selection part isn't either.
What am I doing wrong with the getSelection() and what do I need to do to insert a link into said selection? (to clarify, not to replace the text with a link, but to insert a link into the text)
//Open trigger to get menu
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Scry', 'serumVisions')
.addToUi();
}
//Installation trigger
function onInstall(e) {
onOpen(e);
}
//I'm not sure if I need to do this but in case; declare var elements first
var elements
// Get selected text (not working)
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var elements = selection.getRangeElements();
Logger.log(elements);
} else {
var elements = "Lack of selection"
Logger.log("Lack of selection");
}
}
//Test run
// insert here
// Search Function
function searchFunction(nameTag) {
// API call + inserted Value
let URL = "https://api.scryfall.com/cards/named?exact=" + nameTag;
// Grabbing response
let response = UrlFetchApp.fetch(URL, {muteHttpExceptions: true});
let json = response.getContentText();
// Translation
let data = JSON.parse(json);
// Jackpot
let link = data.scryfall_uri;
// Output
Logger.log(link);
}
// Test run
searchFunction("Lightning Bolt");
//Let's hope this works how I think it works
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
// Unsure what class I'm supposed to use, this doesn't
const insertLink = DocumentApp.getActiveDocument().getSelection().newRichTextValue()
.setLinkUrl(linkage);
Logger.log(linkage);
}
For the first part, I tried the getSelection() and getCursor() examples from the Google documentation but they don't seem to work, they all just keep returning null.
For the inserting link bit, I read all those classes from the Spreadsheet section of the documentation, at the time I was unaware but now knowing, I haven't been able to find a version of the same task for Google Docs. Maybe it works but I'm writing it wrong as well, idk.
Modification points:
In your script, the functions of getSelectedText() and searchFunction(nameTag) return no values. I think that this might be the reason for your current issue of they all just keep returning null..
elements of var elements = selection.getRangeElements(); is not text data.
DocumentApp.getActiveDocument().getSelection() has no method of newRichTextValue().
In the case of searchFunction("Lightning Bolt");, when the script is run, this function is always run. Please be careful about this.
When these points are reflected in your script, how about the following modification?
Modified script:
Please remove searchFunction("Lightning Bolt");. And, in this case, var elements is not used. Please be careful about this.
From your script, I guessed that in your situation, you might have wanted to run serumVisions(). And also, I thought that you might have wanted to run the individual function. So, I modified your script as follows.
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
var text = "";
if (selection) {
text = selection.getRangeElements()[0].getElement().asText().getText().trim();
Logger.log(text);
} else {
text = "Lack of selection"
Logger.log("Lack of selection");
}
return text;
}
function searchFunction(nameTag) {
let URL = "https://api.scryfall.com/cards/named?exact=" + encodeURIComponent(nameTag);
let response = UrlFetchApp.fetch(URL, { muteHttpExceptions: true });
let json = response.getContentText();
let data = JSON.parse(json);
let link = data.scryfall_uri;
Logger.log(link);
return link;
}
// Please run this function.
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
if (linkage) {
Logger.log(linkage);
DocumentApp.getActiveDocument().getSelection().getRangeElements()[0].getElement().asText().editAsText().setLinkUrl(linkage);
}
}
When you select the text of "Lightning Bolt" in the Google Document and run the function serumVisions(), the text of Lightning Bolt is retrieved, and the URL like https://scryfall.com/card/2x2/117/lightning-bolt?utm_source=api is retrieved. And, this link is set to the selected text of "Lightning Bolt".
Reference:
getSelection()

How to clear certain cells on opening a spreadsheet

I am trying to get my Google Sheet to clear certain cells on opening it. I've never added Apps Script to any sheet, so step by sp instructions will be greatly appreciated.
I'm getting an error when trying to deploy the script below.
function onOpen() {
function clearRange() {
// replace 'Sheet2' with your actual sheet name
// replace '1AsVArsUf5DaIXqzyPEokCRkPVglxSPW4NgWg_PVtLhA/edit#gid=1395849459' with your actual sheet ID
var sheetActive = SpreadsheetApp.openById("1AsVArsUf5DaIXqzyPEokCRkPVglxSPW4NgWg_PVtLhA/edit#gid=1395849459").getSheetByName("Sheet2");
sheetActive.getRange('G83,G143,E143,G210,G221').clearContent();
}
}
Clear Ranges:
function onOpen() {
clearRange()
}
function clearRange() {
const ss = SpreadsheetApp.openById("1AsVArsUf5DaIXqzyPEokCRkPVglxSPW4NgWg_PVtLhA/edit#gid=1395849459");
const sh = ss.getSheetByName("Sheet2");
const rgl = sh.getRangeList(['G83','G143','E143','G210','G221']).getRanges().forEach(r => r.clearContent())
}
You probably need an installable trigger because you are using openById()
Sheet.getRangeList

How to update PivotTable with Google App Script?

I need help to update a pivotTable with google app script. Is there a good way to do it?
The pivotTable will create with the following function:
function pivotTableTest() {
// Ask for the source spreadsheet name
// Has to enter with range!
var ui = SpreadsheetApp.getUi();
var sourceSpreadsheet = ui.prompt("Enter the sheet name with range:");
Logger.log(sourceSpreadsheet.getResponseText());
Logger.log(sourceSpreadsheet.getSelectedButton());
// Create PivotTable
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceData = spreadsheet.getRange(sourceSpreadsheet.getResponseText());
var pivotTable = spreadsheet.getRange('B3').createPivotTable(sourceData);
// Add Rows
var pivotGroup = pivotTable.addRowGroup(3);
Now I need a function to add Values to the pivotTable:
function addValue() {
//???????????????????????????????????????
//pivotValue = pivotTable.addPivotValue(31, SpreadsheetApp.PivotTableSummarizeFunction.SUM);
}
But I don't know how to write the function, because the only way to do this was create a new PivotTable..
Thanks for your help!

Google sheets scripts function UrlFetchApp.fetch does not run from .onEdit(e) but works from editor

I have created a google sheet with a lot of info for a beach volleyball cup and I want to call an API I have created when a checkbox is checked in this sheet.
function onEdit(e){
const ui = SpreadsheetApp.getUi();
const spreadsheets = SpreadsheetApp.getActive();
const configSheet = spreadsheets.getSheetByName("Config")
var tourneyId = String(configSheet.getRange(2,4).getValue())
var tourneyTitle = String(configSheet.getRange(2,5).getValue())
var sheet = spreadsheets.getActiveSheet()
if (sheet.getName() == "LiveScore"){
var actRng = sheet.getActiveRange();
var editColumn = actRng.getColumn();
var rowIndex = actRng.getRowIndex();
actRng = actRng.getCell(1, 1);
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
if(editColumn == 7 && rowIndex != 1){
onStartBroadcastClicked(actRng, ui, sheet, rowIndex, editColumn, tourneyTitle);
}
}
}
There is never any problems with this part as I see it. But when i get into the function onStartBroadcastClicked:
function onStartBroadcastClicked(actRng, ui, sheet, rowIndex, editColumn, tourneyTitle){
var homeTeam = String(sheet.getRange(rowIndex, 14).getValue());
... // more setting variables
var endTime = new Date(startTime.getTime() + MILLIS_PER_MATCH);
if(actRng.isChecked()){
var response = ui.alert("You are about to start a new broadcast. Are you sure?" +
"\n Title: " + title, ui.ButtonSet.YES_NO);
if (response == ui.Button.YES) {
var httpRequest = "https://someUrl";
var options =
{
'method':'POST',
'contentType': 'application/json',
'payload' : JSON.stringify({
"title" : title,
... // setting all variables
"description" : description
}),
'muteHttpExceptions' : true,
'headers' : {
"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ":" + PASSWORD)
}
};
ui.alert("Waiting.......")
var result = UrlFetchApp.fetch(httpRequest, options);
ui.alert(result.getContentText())
The issue is that it always gets to the line ui.alert("Waiting......."), but when triggered from the checkbox, it never succeeds the http POST request. If I click play inside the editor, it succeeds and I got the response in the alertbox.
Could it be some timeout or some autosave issues? Does anyone have any idea if where to keep looking? I've been stuck here for some time now and I would be really happy if anyone can point me to the correct direction.
The modification point of your issue is to use the installable trigger of OnEdit event. When the methods which are required to authorize used at the simple trigger, the error occurs. This situation makes us think that it seems the script doesn't work.
In order to avoid this error, please use the installable triggers of OnEdit event trigger.
As an important point, before you install the trigger, please rename the function name of onEdit() to other name. And install the renamed function name as the OnEdit event trigger. By this, the duplicate run of onEdit() can be prevented. If onEdit() function is installed as the installable trigger, when a cell is edited, the function is run 2 times. Ref.
By above settings, when the cell is edited, UrlFetchApp.fetch() works.
References:
Simple Triggers
Installable Triggers
Asynchronous Processing using Event Triggers
I was able to get a script to work with a trigger if I created the script from script.google.com and call the Google Sheet and tab from the script. I'm manually entered in my API calls per cell within a specified Row:
function fetchUrls() {
var spreadsheetId = "ENTER GOOGLE SHEET ID";
var spreadsheet = SpreadsheetApp.openById(spreadsheetId);
var sheet = spreadsheet.getSheetByName("ENTER SHEET NAME");
var range = sheet.getRange("ENTER RANGE OR FULL COLUMN"); // specify the range of cells in column B
var urls = range.getValues(); // get the values of the cells and store them
in an array
var cache = CacheService.getScriptCache();
for (var i = 0; i < urls.length; i++) {
if(urls[i][0] != "") { // check if the current cell is not empty
var url = urls[i][0];
var result = cache.get(url);
if(!result) {
var response = UrlFetchApp.fetch(url);
result = response.getContentText();
cache.put(url, result, 21600);
}
sheet.getRange(i+1,3).setValue(result); // set the value of the current cell to the result of the API call in column C
}
}
}

Export data from Google AppMaker Datasource automatically

Does anyone know how we can generate report from data in datasource in Google AppMaker automatically (e.g generate report at 12a.m.) instead of manually click export data in deployments every time user need the report.
I have seen something similar on Exporting data out of Google AppMaker but also no one tried to answer that.
Really appreciate if there is anyone who know how to solve this :)
This can be achieved by using Installable Triggers.
Say for example, you have a model with students data that has three fields; name(string), age(number) and grade(number). On the server script you can write something like this:
//define function to do the data export
function dataExport() {
//create sheet to populate data
var fileName = "Students List " + new Date(); //define file name
var newExport = SpreadsheetApp.create(fileName); // create new spreadsheet
var header = ["Name", "Age", "Grade"]; //define header
newExport.appendRow(header); // append header to spreadsheet
//get all students records
var ds = app.models.students.newQuery();
var allStudents = ds.run();
for(var i=0; i< allStudents.length; i++) {
//get each student data
var student = allStudents[i];
var studentName = student.name;
var studentAge = student.age;
var studentGrade = student.grade;
var newRow = [studentName, studentAge, studentGrade]; //save studen data in a row
newExport.appendRow(newRow); //append student data row to spreadsheet
}
console.log("Finished Exporting Student Data");
}
//invoke function to set up the auto export
function exportData(){
//check if there is an existing trigger for this process
var existingTrigger = PropertiesService.getScriptProperties().getProperty("autoExportTrigger");
//if the trigger already exists, inform user about it
if(existingTrigger) {
return "Auto export is already set";
} else { // if the trigger does not exists, continue to set the trigger to auto export data
//runs the script every day at 1am on the time zone specified
var newTrigger = ScriptApp.newTrigger('dataExport')
.timeBased()
.atHour(1)
.everyDays(1)
.inTimezone("America/Chicago")
.create();
var triggerId = newTrigger.getUniqueId();
if(triggerId) {
PropertiesService.getScriptProperties().setProperty("autoExportTrigger", triggerId);
return "Auto export has been set successfully!";
} else {
return "Failed to set auto export. Try again please";
}
}
}
Then, to delete/stop the auto export, in case you need to, you can write the following on the server script too:
function deleteTrigger() {
//get the current auto export trigger id
var triggerId = PropertiesService.getScriptProperties().getProperty("autoExportTrigger");
//get all triggers
var allTriggers = ScriptApp.getProjectTriggers();
//loop over all triggers.
for (var i = 0; i < allTriggers.length; i++) {
// If the current trigger is the correct one, delete it.
if (allTriggers[i].getUniqueId() === triggerId) {
ScriptApp.deleteTrigger(allTriggers[i]);
break;
//else delete all the triggers found
} else {
ScriptApp.deleteTrigger(allTriggers[i]);
}
}
PropertiesService.getScriptProperties().deleteProperty("autoExportTrigger");
return "Auto export has been cancelled";
}
You can check the demo app right here.
The reference to the script properties service is here.
The reference to the Time Zones list is here.
I hope this helps!
It seems that you are looking for daily database backups. App Maker Team recommends migrating apps to Cloud SQL if you haven't done this so far. Once you start using Cloud SQL as your data backend you can configure backups through Google Cloud Console:
https://cloud.google.com/sql/docs/mysql/backup-recovery/backups

Categories