Calling library function from html in that library - google-apps-script

In order to share with my colleagues the AppsScript code I am developing, I created a standalone project used as a library in our Docs template.
This library contains:
a .gs file for the server side code
a .html file for the client side sidebar
In the sidebar, I have a button which triggers a call to a function from the library with a parameter.
The javascript call is the following:
google.script.run
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
})
.test();
I read on other pages that the library code wasn't exposed so the test function is in fact in the AppsScript code of my Docs and calls the equivalent library function.
As it was suggested here: Can a Google Spreadsheet Apps Script library contain a user dialog?
Code in the Docs AppsScript:
function test()
{
myLibrary.test();
}
Code in myLibrary library:
function test()
{
DocumentApp.getUi().alert('test');
}
The problem is that the failure handler from the javascript returns a ScriptError stating that I need to have the authorization to perform this action.
Any ideas of what I am doing wrong?
PS: I know I could make an add-on but this is not something I can easily do inside my company :)

Yes, when you use the html code (sidebar) from your library it'll call the test() function inside the script bound to the document rather that the one in the library.
You need to request permission to the user to be able to prompt UI elements, you can do this with a custom menu [1].
Also, the users need to have at least read access on the library [2]. I add the withSuccessHandler function [3] to show the response from client-side in the sidebar. The following code worked for me:
Script bound to the document:
function onOpen() {
DocumentApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.createMenu('Custom Menu')
.addItem('Show sidebar', 'showSidebar')
.addToUi();
}
function showSidebar() {
myLibrary.showSidebarLibrary();
}
//
function test() {
myLibrary.test();
}
Library:
code.gs
function showSidebarLibrary() {
var html = HtmlService.createHtmlOutputFromFile('Page')
.setTitle('My custom sidebar')
.setWidth(300);
DocumentApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showSidebar(html);
}
function test() {
DocumentApp.getUi().alert('test');
return "Success";
}
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Hello, world!<br>
<input type="button" value="Alert" onclick="alert()" /><br>
<input type="button" value="Close" onclick="google.script.host.close()" />
<p id="msg">Replace message with response<p>
</body>
<script>
function alert() {
google.script.run.withFailureHandler(handler).withSuccessHandler(handler).test();
}
function handler(msg) {
document.getElementById("msg").innerHTML = msg;
}
</script>
</html>
[1] https://developers.google.com/apps-script/guides/menus
[2] https://developers.google.com/apps-script/guides/libraries#gaining_access_to_a_library_and_including_it_in_your_project
[3] https://developers.google.com/apps-script/guides/html/communication#success_handlers

Related

onOpen event does not not launch a dialog box

I have a sheet that I send out to staff (copies that are shared) but when I copy this the function onOpen does not launch the dialog box.
function onOpen() {
SpreadsheetApp.getUi()
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('Index');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Math Sheet Directions');
}
Take a deep look on the next thread : onOpen not executing?
As you can see from the thread and Issue Tracker:
Google has restriction for onOpen functionality
Is there a different way to achieve your goal?
You can create a red button "Show URLs" and assign it a function.
For example:
function openDialogBox() {
// your html content here
var html = "<a href='https://google.com'>Google.com</a><br /><a href='https://stackoverflow.com'>Stackoverflow.com</a>" ;
var htmlOutput = HtmlService
.createHtmlOutput(html)
.setWidth(250)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'URL links');
}
This is how it looks like:
We don't have any restriction here.
I know this method doesn't help you, but probably this is the only way to achieve similar behavior of what you want to do :)
Reference
Google Apps Script - onOpen()
Google Apps Script - Class HtmlService
Google Apps Script Guide - HTML Service: Create and Serve HTML

Show dialog Google-Apps-Script for a shared link

The code below works on a document I am the owner of. When I share a link to it (with edit privileges), it does not respond for the editor. Any idea what is the cause of it?
function onEdit(event) {
showDialog();
} // I also have this function listed under triggers for 'On edit' events
function showDialog() {
var ui = HtmlService.createHtmlOutputFromFile('revRequestUI')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(700)
.setHeight(320);
SpreadsheetApp.getUi()
.showModalDialog(ui, ' ');
}

Cannot find custom menu and sidebar in the published add-on

I am trying to publish a Google Sheet add-on with the unlisted option: Only people with the link can see it. Here is the code: Code.gs:
function myFun() {
return "myFunValue"
}
function onInstall() {
onOpen()
}
function onOpen() {
var html = HtmlService.createHtmlOutputFromFile('Index.html') //your html page name
.setTitle('My custom sidebar')
.setWidth(300);
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Use in this spreadsheet', 'use')
.addToUi();
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showSidebar(html);
}
function use() {
var title = 'Date Custom Functions';
var message = 'Message of use';
var ui = SpreadsheetApp.getUi();
ui.alert(title, message, ui.ButtonSet.OK);
}
Index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
super add-on, with custom function "=myFun()" and custom menu
</body>
</html>
Here is the link:
https://chrome.google.com/webstore/detail/functionmenuside/bmojfiljhggogegocdkjdlaoohbkcmod?authuser=0
This add-on works on its own Google Sheet. However, after publishing, when I click on +Free, it opens a new Google Sheet, I can find FunctionMenuSide in the Add-ons. The custom function works, whereas there is no sidebar, and we cannot find the custom menu Use in this spreadsheet. It seems that onOpen is not executed.
Does anyone know how to fix this?
Edit 1:, in the console, there are messages:
1739997376-ritz_waffle_integrated_i18n_ritzmaestro.js:105 Google Apps Script: You do not have permission to call createHtmlOutputFromFile.
You are trying to open the sidebar in the onOpen() function. This won't work because of the way that simple triggers work with Google Apps Script.
Instead, create another function that opens the sidebar and adds that function as an item in your add-on menu. Then your user can open the sidebar themselves from the add-on menu.

How to call Google Apps Script encapsulated function from html template

Hi I am using Google App Scripts on a Google Sheet and I wanted to organize my code, so I tried encapsulating some of the functions. However, I can't seem to figure out how to call the encapsulated functions from the html templates.
Does anyone know if it is possible to call an encapsulated function with google.script.run from an html template?
Example:
Code.gs
function onOpen(e){
var menu = SpreadsheetApp.getUi().createMenu('Document Routing')
.addItem('View/Edit My Routes', 'ViewMyRoutes')
.addToUi();
}
function ViewMyRoutes() {
var html = HtmlService.createHtmlOutputFromFile('MyRoutes')
.setTitle('My Routes')
.setWidth(300);
SpreadsheetApp.getUi()
.showSidebar(html);
}
User.gs
var User = function(){
return {
GetMyRoutes: function (){
var userProperties = PropertiesService.getUserProperties();
var routeData = userProperties.getProperty("SpreadsheetRoutes");
return routeData;
}
};
}();
Sample.html
<h1>Edit Route</h1>
<select id="EditRoute" onchange="LoadSelectedRoute()"></select>
<div id='divRoutes'></div>
<script>
function LoadEditDropDown(){
google.script.run
.withFailureHandler(onFailure)
.withSuccessHandler(OnGetRoutesSuccess)
.User.GetMyRoutes();
function OnGetRoutesSuccess(scriptProperties){
//do stuff with scriptProperties here
}
}
LoadEditDropDown();
</script>
How about this? In such case, I use this way. But I don't know whether this is the best way. I'm sorry. I worry about that this may be the opposite way for you want.
1. Please add this function to GAS
function UserGetMyRoutes() {
return User.GetMyRoutes();
}
2. Please modify google.script.run as follows
From :
google.script.run
.withFailureHandler(onFailure)
.withSuccessHandler(OnGetRoutesSuccess)
.User.GetMyRoutes();
To :
google.script.run
.withFailureHandler(onFailure)
.withSuccessHandler(OnGetRoutesSuccess)
.UserGetMyRoutes();

How to use scriptlets in HTMLOutput in Google Apps Script

I'm loading a modal dialog with:
var html = HtmlService.createHtmlOutputFromFile('File')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(1000)
.setHeight(700);
SpreadsheetApp.getUi()
.showModalDialog(html, 'My Page');
Now, in File.HTML, I want to load another HTML file with CSS settings, how do I do that?
I've tried including it as in HtmlTemplate using scriptlets but it doesn't work:
<?!= include('File'); ?>
EDIT:
I have defined the include function in code.gs:
function include (file) {
return HtmlService.createTemplateFromFile(file).evaluate().getContent();
}
The problem is that you are using:
createHtmlOutputFromFile
instead of:
createTemplateFromFile
You need to create a template:
This is what you are seeing:
The scriptlet is not running, but being interpreted as text.
This is what you want to see:
Here is how the code should be:
Code.gs
// Use this code for Google Docs, Forms, or new Sheets.
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Dialog')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createTemplateFromFile('index')
.evaluate();//This is necessary
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Dialog title');
}
function include(File) {
return HtmlService.createHtmlOutputFromFile(File).getContent();
};
index.html
<?!= include('File'); ?>
Hello, world!
<input type="button" value="Close"
onclick="google.script.host.close()" />
File.html
<div>
This is a test. it worked!
</div>
Basically, you need to change:
var html = HtmlService.createHtmlOutputFromFile('index')
to:
var html = HtmlService.createTemplateFromFile('index')
Create a TEMPLATE from file.
And I also changed the code to this:
function openDialog() {
var html = HtmlService.createTemplateFromFile('index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
Original answer:
include is not something like a keyword or a built in function. You need to create a function in a .gs script file named include.
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
};
Also, you can't mix the HTML Service and the UI Service. I don't know if that's what you are trying to do, but I thought I'd mention it.
What you want to accomplish is describe in the documentation here:
Documentation - Best Practices