Google Apps Script HTMLservices append HTML - google-apps-script

Hi GAS StackOverflow guides,
How do you append another HTML code/file after the initial doGet mentioned here? https://developers.google.com/apps-script/html_service#HTMLFiles
It says it can append using HtmlOutput class but no success with:
function doSomething() {
//append another HTML file
return HtmlService.createHtmlOutputFromFile('headers');
}
function doSomething2() {
//append another HTML file
return HtmlService.createHtmlOutputFromFile.append('headers');
}
Thanks.

The append method on an HtmlOutput is for appending in the initial doGet function (if you are building up your HTML piece by piece). You can't use it to append more stuff later, but you can use the regular document.append() that you'd use in any other client-side JavaScript to do this. Something like this:
On the client
google.script.run.withSuccessHandler(function(x) { document.append(x); }).doSomething2()
On the server
function doSomething2() { return "the stuff I want to append"; }

Related

Can't Get Specific .html to load on doGet() | WebApp

I am trying to load a specific .html depending on the current cell's Text (either .value() or .getdisplayValue()).
However, for some reason only the Payroll.html file is ever being fired, even though the current cell's text is "Click To Upload Receipt"
function doGet(e) {
if (sheet.getActiveCell().getValue() === "Click To Upload Receipt") {
var htmlOutput = HtmlService.createTemplateFromFile('UploadFile');
} else {
var htmlOutput = HtmlService.createTemplateFromFile('Payroll');
}
htmlOutput.message = '';
return htmlOutput.evaluate();
}
I have ReDeployed my WebApp and set the URL of this as a link on the current cell.
Please let me know if you need any specific information to assist. Thank you all.
An Apps Script webapp (container bound or not) has no concept of an "active cell," in the doGet or doPost event handler.
Instead, you should invoke the doGet endpoint with a URL query parameter containing the desired template to display. You can access this from the event object received by the doGet call.
For example,
https://scripts.google.com/a/.......?action=do%20payroll
This would invoke your doGet handler with a function argument that has a property "parameter" with the property named "action" and the value "do payroll".
You could then load the desired parameter by inspecting this value, and provide a fallback if an unknown value is provided:
function doGet(eventObj) {
const action = eventObj.parameter.action;
if (action === "do payroll") {
// Do stuff
} else if (action === "do receipt") {
// Do other stuff
} else {
// Provide fallback for incorrect user input
}
}
This may be helpful: https://developers.google.com/apps-script/guides/web
Despite that sheet has not being defined, getActiveCell() doesn't work as you assumed for Google Apps Script web apps, but it might work for a dialog of sidebar.
The above because the web application instance hasn't the "active" context. If web app code belongs to a spreadsheet bounded project, SpreadsheetApp.getActiveSpreadsheet() will return the bounded spreadsheet but methods like getActiveCell and getActiveRange will return A1 of the first sheet.
Instead you using the "active cell" you could include a query string (i.e. ?page=page_name
A very simplistic way to implement this:
function doGet(e){
const template = HtmlService.createTemplateFromFile(e.parameter.page || 'index');
return template.evaluate();
}
Related
Linking to another HTML page in Google Apps Script
Multi-page site in Google Apps Script: How to invoke doGet() through jquery or javascript?
Resources
https://developers.google.com/apps-script/guides/web

How can I use a Library, which displays drafts and sends email into a Container-Bound Project?

I have 2 Google Apps Script Projects.
SheetsLib - This is a Library which I created, it contains my go-to functions.
TestFile - This is a container-bound script, which utilizes the SheetsLib.
SheetsLib contains the following functions which are relevant for this question:
displayDraftsSelector - Displays the draftSelector Html Page in the Sidebar.
draftSelector - Html file, which contains a js script as well that calls back-end function to populate a <select>
getDraftsArr - Server function which returns all gmail drafts from the user.
The SheetsLib function(s) do work, i.e. I have test functions to confirm that. My goal is to enhance this library, so that I can use it in multiple projects with the functionality to allow a user to choose an existing Gmail Draft and send it to selected users (in the active Spreadsheet).
PROBLEM
In my new container-bound script, which has access to the Library, I can only show the sidebar but not call a back-end function (which resides in the Library) when I press a button in sidebar:
I load the view successfully using displayDraftsSelector() which shows the view draftSelector. This is all functionality from the Library.
Then, the view calls the getDraftsArr() and this is what gets the error. But that function does exist in the Library (and it does work as intended).
The following is the error I see in the console when the sidebar loads:
Uncaught TypeError: google.script.run.withSuccessHandler(...).withFailureHandler(...).getDraftsArr is not a function
What should happen ideally is that, the back-end function getDraftsArr() is called and its result populates the select item. Then the user can select one draft in the sidebar. When the user confirms using a button, the active rows are the recipients. Overall, this all works when I copy-> paste, but what cannot figure out is how to keep the functionality in a library.
The following is the function located in the Library which I am trying to call.
// back-end in Library Project
function getDraftsArr(){
let output = [];
const messages = GmailApp.getDraftMessages();
messages.forEach( message => {
output.push({
id: message.getId(),
subject: message.getSubject()
});
});
return JSON.stringify(output)
}
The following is in the back-end of the library
// front-end in Library Project
<select id="draftsSelect"></select>
<script>
function getDrafts(){
const draftsSelect = document.getElementById("draftsSelect");
google.script.run
.withSuccessHandler( updateDrafts )
.getDraftsArr();
function updateDrafts( drafts ){
var options = "";
var draftsParsed = JSON.parse(drafts);
draftsParsed.forEach( draft => {
options += "<option value='" + draft.id + "'>" + draft.subject + "</option>";
});
draftsSelect.innerHTML = options; }
}
</script>
Thanks to #Rubén for the link to this: stackoverflow.com/q/59271952/1595451
Basically the solution was to create a function in my container-script with the same name as the back-end function which are in the library, which then call the library.
So in my Library I had getDraftsArr(){}before, and now I added the following to my container-bound project:
function getDraftsArr(){
return SheetsLib.getDraftsArr()
}
That did the trick.
If you can create a dummy function. Then the dummy function to create is this one:
function executeLibraryFunctionsByName(funcname) {
libraryname[funcname]();
}
This function will allow you to call all of your library functions by name. I'm not sure that this will work if your libary name has a space in it. In that case change it's name. Note: don't put quotations around the libraryname. Just write the libaryname with no quotes and I would avoid spaces and it becomes the 'this' for your function.
As an example I have a library xyzSUS1 and I can use a button like this:
<input type="button" value="test" onClick="google.script.run.callLibraryFunctionsByName('selectColumnsSkipHeader');" />
in my sidebar to run the library function xyzSUS1.selectColumnsSkipHeader() .
the command in function declaration in my gs code is this:
function callLibraryFunctionsByName(funcname) {
xyzSUS1[funcname]();//the this for funcname because xyzSUS1
}

How to use parameters that go to a script in html content?

I am new to using Google script, but not completely new to programming.
I have looked at some examples and they generate HTML output like this:
function doGet(e) {
return HtmlService.createHtmloutputFromFile('form.html')
}
I would like to pass a parameter to my script to use that in the output.
I have gotten as far as that I can use this in the function:
var room= e.parameter.room
So when I execute my script with url?room=test
I do get the value for that parameter.
But how can I use that variable room that I create in the HTML output and other code?
I have been looking at createTemplateFromFile but I am not getting anywhere.
Hope someone can point me in the right direction of what constructs and command to look at.
You can directly get query parameters client side1:
form.html
<script>
google.script.url.getLocation(function(location) {
alert(location.parameter.room); //alerts "test" on loading "url?room=test"
});
</script>
Alternatively, You can use scriplets to load html2:
code.gs
function doGet(e) {
var temp = HtmlService.createTemplateFromFile('form');
temp.room = e.parameter.room;
return temp.evaluate();
}
form.html:
<script>
alert('<?=room?>'); //Printing scriplets
</script>

Display variable as html in Google App Script?

Let's say we have a variable. This variable was created in google app script. On that app script project, you have two files. First, the .gs file, where the variable came from. Next, you have the html file. How do you transfer the variable to html?
GAS:
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function items() {
var exmp = 45;
document.getElementById("test").innerHTML = "You have " + exmp + " items";
HTML:
<script>
google.script.run.items();
</script>
<div id="test"></div>
However, this doesn't work. How can I make this work?
If you read over the Private Functions section of the HTML service documentation, you'll find an example that does almost exactly what you're trying. The code below adapts that example to yours.
You need to keep the GAS server stuff separate from the HTML client stuff. For example, document.getElementById("test").innerHTML = ... means nothing in the context of the server / GAS code. Instead, the modification of the document will be done by Javascript on the client side - in this case, by a success handler.
A success handler is a client-side Javascript callback function that will receive the asynchronous response from your server function items().
Client-side calls to server-side functions are asynchronous: after the
browser requests that the server run the function doSomething(), the
browser continues immediately to the next line of code without waiting
for a response.
This means that there is no waiting for the return code from the call to your server function... the browser just keeps going. You'll see this in this example, as the "More loading..." text gets displayed after the google.script.run call, but before the response is received.
What if items() needs to do something more advanced... like read info from a spreadsheet? Go ahead and change it... just make sure that you return the text you want displayed, and that what you're returning is going to be valid HTML (so the innerHTML operation is OK).
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function items() {
Utilities.sleep(5000); // Added to allow time to see the div content change
var exmp = 45;
return( "You have " + exmp + " items" );
}
index.html
<div id="test">Loading...</div>
<script type="text/javascript">
function onSuccess(items) {
document.getElementById('test').innerHTML = items;
}
google.script.run.withSuccessHandler(onSuccess).items();
document.getElementById('test').innerHTML = "More loading...";
</script>
You need first to create the HTML using the createHTMLOutput function
In order for you to append strings youo have to use the var.append method
function items(){
var email = Session.getActiveUser().getEmail();
var output = HtmlService.createHtmlOutput(email);
var string1 = HtmlService.createHtmlOutput('<p>You have </p>')
string1.append(output);
string2= HtmlService.createHtmlOutput('<p> items</p>')
string1.append(string2);
Logger.log(string1.getContent());
}
Reference

Error when trying to get the URL of a page in a Google Apps Script

I am writing a Google Apps Script to be embedded into Google Sites to retrieve the names and URLs for child pages of the current page. When I call the getURL() function I am getting the following error:
'TypeError: Cannot find function getURL in object WebPage.'
My code is as follows:
function doGet() {
var app = UiApp.createApplication();
var pages = SitesApp.getActivePage().getChildren();
for (var i = 0; i < pages.length; i++) {
Logger.log(pages[i].getURL());
}
return app;
}
I am new to Google Apps Scripts so am struggling to work out what this means. Any help would be greatly appreciated.
Use pages[i].getUrl()
You should use the autocomplete feature in the script editor to avoid such typing errors (control space after the dot : page[i].here type CTRL space and you'll see all possible methods...)
Note : the general rule in javascript is to use the so called camelCase format : getRange, createLabel ... there are only a few exceptions like setHTML but every rule must have exceptions doesn't it ?