I'm developing a Chrome extension that has access to Google Sheets using a standalone Google Apps Script.
I need help to be able to navigate and highlight given variable row from my extension. either using Apps Script or some other way.
I've tried this code in google apps script.
function navigateToRow(parameters) {
var ss = SpreadsheetApp.openByUrl(parameters.url)
var sheet = ss.getSheets()[0]
var range = sheet.getRange('A1:D10'); // will get range from parameters in future
range.activate();
}
There is another solution that could solve the problem, but it refreshes the page: using url parameters, e.g.
https://docs.google.com/spreadsheets/d/<spreadsheet id>/edit#gid=<sheet id>&range=<a1 notation>.
Try something like :
var range = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(1, 1);
SpreadsheetApp.setActiveRange(range);
Reference : https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#setactiverangerange
Solved using these lines of code inside the content-script.
hash = window.location.hash.split('&range=')[0]
hash += `&range=${currentRowInput.value}:${currentRowInput.value}#`;
window.location.hash = hash
Related
Is there a way I can access data, stored within a spreadsheet-file from the library script?
I want to use 1 Google Apps Script from multiple Google Spreadsheet files within my Google Drive.
I followed this answer: "you could use Libraries. The idea is that you create one script that you use as a library" and could successfully import the library to my project.
In order to work, the scripts within the library need some of the cell-values stored in the google sheet files. I know how to access the script via a helper function in my sheet-bound script file. For example:
function loc_my_credits()
{
SISTRIXAbfrageFreigabe.my_credits();
}
Whilst "SISTRIXAbfrageFreigabe" is the library name, and my_credits a function within the library.
When I call loc_my_credits from sheets, nothing happens. My best guess: the script cant read data from the spreadsheet file it needs to execute.
The my_credits script from the library file looks like this:
function my_credits(){
// Base URL to access customsearch
var urlTemplate = "https://api.sistrix.com/credits?api_key=%KEY%";
// initialize sheets: 1. Get the spreadsheet, 2. Get the first and the second sheets in this spreadsheet
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var inputSheet = spreadSheet.getSheets()[0];
// Script-specific credentials & search engine
var sistrix_Apikey = inputSheet.getRange('A2').getValue();
var url = urlTemplate.replace("%KEY%", encodeURIComponent(sistrix_Apikey));
var params = {
muteHttpExceptions: true
};
var xml = UrlFetchApp.fetch(url).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var items = document.getRootElement().getChildren();
for (var i = 0; i < items.length; i++) {
if(items[i].getName() == 'answer'){
var answer = items[i].getChildren();
return answer[0].getAttribute('value').getValue();
}
}
return 0;
}
Is there a way I can access the data stored in the spreadsheet file from the library script?
I'm writing this answer as a community wiki, since the issue was resolved from the comments section, in order to provide a proper response to the question.
The problem was related to the usage of methods that need scopes that require authorization, therefore it would be expected that simple triggers would show the error:
You do not have permission to call SpreadsheetApp.openById
Google's documentation states that installable triggers would solve the problem:
Installable triggers, however, offer more flexibility than simple triggers: they can call services that require authorization
According to s.Panse, the usage of installable triggers has resolved the issue in this case.
References:
google script openById : You do not have permission to perform that action
Installable Triggers
I have a script that creates a document during runtime and attach it to a variable.
I need to insert images to it using a script.
Here is my code:
var modulo = "foo";
var nomeDoc = "bar";
let doc = DocumentApp.create("Validação escopo ("+ modulo +") cliente: " + nomeDoc);
var body = doc.getBody();
var imgPDF = body.appendImage(blob);
How do i pass an image as "blob" inside the variable: imgPDF?
Important: The image is in the Spreadsheet that calls this function.
On January 19, 2022, 2 Classes for using the inner cell image were added to the Spreadsheet service. Ref But, in the current stage, the image can be put into a cell. But, unfortunately, the image in the cell cannot be retrieved. I think that this might be a bug. And also, these Classes cannot retrieve the images on a cell as the blob and the image URL. I think that this is the specification.
So, as the current workaround, I thought that in your situation, in the current stage, this method can be used. Ref
In this workaround, a Google Apps Script library might be able to be used. Ref This library can retrieve both the image in a cell and the image on a cell.
Usage:
1. Install Google Apps Script library.
You can see the method for installing this library at here.
2. Enable Drive API.
In this case, Drive API is used. So, please enable Drive API at Advanced Google services.
3. Sample script.
const spreadsheetId = "###"; // Google Spreadsheet ID
const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId).getSheetByName("Sheet1").getImages();
console.log(res); // You can check the retrieved images at the log.
if (res.length == 0) return;
const blob = res[0].image.blob; // Here, 1st image of Sheet1 is retrieved. Of course, you can choose the image on the sheet.
let doc = DocumentApp.create("Validação escopo (" + modulo + ") cliente: " + nomeDoc);
var body = doc.getBody();
var imgPDF = body.appendImage(blob);
In this case, please declare modulo and nomeDoc.
4. Testing.
When the above script is run, the images are retrieved from "Sheet1" and put the 1st image to the created Document body.
References:
DocsServiceApp
Related thread
How to access new 'in-cell-image' from google apps script?
I am creating a Google Apps Script add-on that is for a Google Spreadsheet, but it needs to be able to access the content of a separate Google Doc, which I am doing using DocumentApp.openById(). I have given the script these scopes:
"oauthScopes": [
"https://www.googleapis.com/auth/documents.readonly",
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/spreadsheets.currentonly"
]
But apparently, that's not enough. The script is telling me it needs the https://www.googleapis.com/auth/documents permission to work properly. However, it seems excessive to give the add-on permission to edit ALL Google Docs files when it just needs to be able to view the content of one. Am I missing something? Is there a way to give it read-only access to a separate Google Docs file?
Here is the function I am using for testing, with most of the document ID censored out:
function getDoc() {
var id = '1NLH----------------------------------------'
var templateFile = DocumentApp.openById(id)
var templateText = templateFile.getBody().getText()
Logger.log(templateText)
}
Thanks!
I believe your goal as follows.
You want to retrieve the text data from Google Document using the following script.
function getDoc() {
var id = '1NLH----------------------------------------'
var templateFile = DocumentApp.openById(id)
var templateText = templateFile.getBody().getText()
Logger.log(templateText)
}
You want to achieve this using the scope of https://www.googleapis.com/auth/documents.readonly and Google Apps Script.
Issue and workaround:
In the current stage, DocumentApp.openById of Document service is used, it is required to use the scope of https://www.googleapis.com/auth/documents. It seems that this is the current specification. So, in this answer, as a workaround, I would like to propose to use Google Docs API instead of Document service. When Google Docs API is used, your script can be achieved using the scope of https://www.googleapis.com/auth/documents.readonly.
When your above script is modified using Google Docs API, it becomes as follows.
Sample script:
Before you use this script, please enable Google Docs API at Advanced Google services. This script can work with only the scope of https://www.googleapis.com/auth/documents.readonly.
function myFunction() {
const documentId = "###"; // Please set the Document ID.
const obj = Docs.Documents.get(documentId);
const text = obj.body.content.reduce((s, c) => {
if (c.paragraph && c.paragraph.elements) {
s += c.paragraph.elements.map(e => e.textRun.content).join("");
}
return s;
}, "");
console.log(text)
}
Reference:
Method: documents.get
I had a prob with my script, which was greatly answered in this question.
Basically custom functions cannot call services that require authorization. However, as far as I understood if I use simple triggers, such as onEdit it could work.
I checked the documentation suggested in the previous question, however I wasn't successful applying that to my code, which you can see below:
function FileName (id) {
var ss = DriveApp.getFileById(id);
return ss.getName();
}
How could I adapt my code to use simple triggers?
Here is a sample sheet that replicates the problem.
I believe your goal as follows.
You want to use your function of FileName as the custom function of Google Spreadsheet.
You want to automatically retrieve the filename when the file ID is put to the column "B".
You want to put the filename to the column "C".
Issue and workaround:
Unfortunately, when the custom function is used, in the current specification, the most methods except several methods (for example, one of them is UrlFetchApp.) that the authorization is required cannot be used. By this, DriveApp.getFileById(id) in your script cannot be used with the custom function. But there is a workaround. At the custom function, UrlFetchApp can be used. In this answer, I would like to propose to use the Web Apps with UrlFetchApp as the wrapper for authorizing. By this, the authorization can be done with the Web Apps. So your function can be run by the custom function.
Usage:
1. Prepare script.
Please copy and paste the following script to the script editor and save it.
const key = "samplekey"; // This is a key for using Web Apps. You can freely modify this.
// This is your function.
function FileName_(id) {
var ss = DriveApp.getFileById(id);
return ss.getName();
}
// Web Apps using as the wrapper for authorizing.
function doGet(e) {
let res = "";
if (e.parameter.key === key) {
try {
res = FileName_(e.parameter.id);
} catch (err) {
res = `Error: ${err.message}`;
}
} else {
res = "Key error.";
}
return ContentService.createTextOutput(JSON.stringify({value: res}));
}
function Filename(id) {
const webAppsUrl = "https://script.google.com/macros/s/###/exec"; // Please set the URL of Web Apps after you set the Web Apps.
const res = UrlFetchApp.fetch(`${webAppsUrl}?id=${id}&key=${key}`);
if (res.getResponseCode() != 200) throw new Error(res.getContentText());
return JSON.parse(res.getContentText()).value;
}
2. Deploy Web Apps.
On the script editor, Open a dialog box by "Publish" -> "Deploy as web app".
Select "Me" for "Execute the app as:".
By this, the script is run as the owner.
Select "Anyone, even anonymous" for "Who has access to the app:".
In this case, the access token is not required to request to Web Apps. But in this sample script, a key for requesting to Web Apps is used.
Click "Deploy" button as new "Project version".
Automatically open a dialog box of "Authorization required".
Click "Review Permissions".
Select own account.
Click "Advanced" at "This app isn't verified".
Click "Go to ### project name ###(unsafe)"
Click "Allow" button.
Click "OK".
Copy the URL of Web Apps. It's like https://script.google.com/macros/s/###/exec.
When you modified the Google Apps Script, please redeploy as new version. By this, the modified script is reflected to Web Apps. Please be careful this.
Please set the URL of https://script.google.com/macros/s/###/exec to url of above script. And please redeploy Web Apps. By this, the latest script is reflected to the Web Apps. So please be careful this.
3. Test this workaround.
When the file ID is put to the cell "A1", please put =filename(A1) to a cell as the custom function. By this, the script is run and the response value is returned.
Note:
Above sample script is a simple sample script for testing your script. So when you want to use the various methods, this post might be useful.
Please use this script with enabling V8.
As other method, I think that when the file ID is manually put to the column "B", the installable OnEdit trigger can be used. The sample script is as follows. Please set the sheet name. And please install the trigger to the function of installedOnEdit. Ref By this, when the file ID is put to the column "B" of sheetName, the file ID is put to the column "C".
function installedOnEdit(e) {
const sheetName = "Sheet1";
const range = e.range;
const sheet = range.getSheet();
if (!(sheet.getSheetName() == sheetName && range.getColumn() == 2 && range.getRow() > 1)) return;
const value = range.getValue();
let res = "";
try {
res = DriveApp.getFileById(value).getName();
} catch(e) {
res = e.message;
}
range.offset(0, 1).setValue(res);
}
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
Enhanced Custom Function for Google Spreadsheet using Web Apps as Wrapper
Related questions
Can you write a Google Sheets function that draws something?
Error when running Youtube Data Service in App Scripts (js) – Daily Limit for Unauthenticated Use Exceeded
How to enable not authorized users to protect the spreadsheet
Changing Owner of the Sheet irrespective of the duplicator
Installable Triggers
As you can draw from the documentation, simple triggers cannot access services that require authorization neither
You have to use installable triggers instead.
However the workflow is very different from custom functions.
In your specific case, you can implement e.g. that when a cell in column A is being edited (that is a new URL is being inserted) - the respective file name is being found and returned into column D.
You can retrieve the value and the row in which the new URL is being inserted with help of event objects.
Sample:
function FileName (event) {
var id = event.value;
var ss = DriveApp.getFileById(id);
var row = event.range.getRow();
var sheet = event.range.getSheet();
// for column D:
var column = 4;
var returnCell = sheet.getRange(row,column);
returnCell.setValue(ss.getName());
}
For using an installable onEdit trigger - bind it to this function through going on Edit > Current project's triggers as explained here.
Code to create an appscript file using appscript editor.
for example you type this:
function msWordExt() {
var ss = SpreadsheetApp.openById('1MUwH0Cm1cwHcTWSCGPp2SePbzs_4QQmtjwOEWOrOkMw');
var sheetName = ss.getSheetByName("Sheet2");
var get = sheetName.getRange(2,3).getValue();
var folder = DriveApp.getFolderById("1rsicZccurujGp5Ye5HUecBIAPf3_h5Pc");
folder.createFile("PLAIN TEXT",get,MimeType.MICROSOFT_WORD);}
So the above code creates a MS Word extension file inside a persons Google Drive.
Now I want to try creating a google appscript file extension using code as well, for example the below code doesn't work but it will help give the gist of what I wish to accomplish:
function appScript() {
var ss = SpreadsheetApp.openById('1MUwH0Cm1cwHcTWSCGPp2SePbzs_4QQmtjwOEWOrOkMw');
var sheetName = ss.getSheetByName("Sheet2");
var get = sheetName.getRange(2,3).getValue();
var folder = DriveApp.getFolderById("1rsicZccurujGp5Ye5HUecBIAPf3_h5Pc");
folder.createFile("This is an appscript file",get,MimeType.GOOGLE_APPS_SCRIPTS);
}
Considerations
You can't use the Drive API to create a Google Apps Scripts Project. Here you can see it's already been reported to Google.
Proposed workaround
You can use the Apps Script API to manage your Apps Script projects. Here is a link to the guide: https://developers.google.com/apps-script/api/samples/manage
Reference
Managing Apps Script Projects