I know how to include CSS or JS files using app script in a web script. but that way includes files content on page lode.
My question is it possible to include partial html page inside the currently opened page?
app script to include CSS or JS
/* #Include JavaScript & CSS & HTML-Partial-Views */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
and I use like this
<?!= include('Css'); ?>
and here is my attempt.
html
<button onclick="getList("users")">show some html content</button>
<div id="users"></div>
<script>
function getList(users){
var listUsers = google.script.run.showHtml(users);
// how to return showHtml result [list of users]
for (var i; i <= listUsers.length; 1++)
{
document.querySelector("#users").innerHTML += <div>listUsers[i]</div>;
}
}
</script>
gs
function users(sheetName, pageName){
// get users from sheet
var ss= SpreadsheetApp.openById("435yh35h45b35nh6hg5bwh455j");
var dataSheet = ss.getSheetByName(sheetName);
var dataRange = dataSheet.getDataRange().getValues();
return dataRange;
}
From one of the code snippets
// how to return showHtml result [list of users]
Try this:
<button onclick="getList('users')">show some html content</button>
<div id="users"></div>
<script>
function getList(users){
var listUsers = google.script.run
.withSuccessHandler((listUsers) => {
let list = '';
for (var i; i < listUsers.length; i++) {
list += `<div>${listUsers[i]}</div>\n`;
}
document.querySelector("#users").innerHTML = list;
})
.showHtml(users);
}
</script>
Changes done
Replaced "users" by 'users'
Added withSuccessHandler with an arrow function as callback.
The arrow function build a string using a for statement (because it was used in the original code) including a div tag using a template literal.
Related
Goal: The purpose is that a sheet will contain information, this information is placed inside a namedrange, the namedrange will be dynamic (the entire column is given a namedrange).
I created a html popup which contains a dropdown list. This dropdown list must contain the list of information from the namedrange.
I am unable to understand how this is to be done. Here is the code below:
function fncOpenMyDialog() {
var htmlDlg = HtmlService.createHtmlOutputFromFile('HTML_myHtml')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(200)
.setHeight(150);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'New File');
};
function onInstall(e) {
onOpen(e);
}
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('New')
.addItem('New Save File Extension','fncOpenMyDialog')
.addToUi();
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select name="nameYouWant" placeholde="File Type">
<option value="something">Word</option>
<option value="anything">MS Excel</option>
<option value="anything">MS Powerpoint</option>
<option value="anything">MS Slides</option>
</select>
<hr/>
<p>Choose a file, which will then be saved into your Google Drive.</p>
<button onmouseup="closeDia()">Close</button>
<button onmouseup="onOpen()">Save</button>
<script>
window.closeDia = function() {
google.script.host.close();
};
window.saveDia = function() {
onOpen();
};
</script>
</body>
</html>
As you can see in my html file, that the extensions are currently hardcoded.
I am trying to make this dynamic, how do I achieve this?
I believe your goal as follows.
You want to put the values to the dropdown list by retrieving from the named range of the Spreadsheet.
In this case, is the named range the same with this thread?
For this, how about this answer?
Modification points:
From google.script.host.close(), I understood that the HTML file of HTML_myHtml is included in the Google Apps Script project. By this, I would like to propose to achieve your goal using google.script.run.
If the named range is the same with your previous question, you can use it by modifying a little.
When above points are reflected to your script, it becomes as follows.
Modified script:
HTML and JavaScript side: HTML_myHtml
Please modify HTML_myHtml as follows.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select id="select" name="nameYouWant" placeholde="File Type"></select>
<hr />
<p>Choose a file, which will then be saved into your Google Drive.</p>
<button onmouseup="closeDia()">Close</button>
<button onmouseup="onOpen()">Save</button>
<script>
google.script.run.withSuccessHandler(v => {
const obj = document.getElementById("select");
v.forEach(e => {
const option = document.createElement("option");
option.text = e;
option.value = e;
obj.appendChild(option);
});
}).readNamedRange();
window.closeDia = function() {
google.script.host.close();
};
window.saveDia = function() {
onOpen();
};
</script>
</body>
</html>
Google Apps Script side: Code.gs
At above HTML, readNamedRange() is used. So please put the following script. If you have the same function names, please modify them. In this script, the values are retrieved from the named range of listDown, and sent to HTML side using google.script.run.
function readNamedRange() {
var activeSheet = SpreadsheetApp.getActiveSheet();
var result = activeSheet.getRange("listDown").getValues();
var end = activeSheet.getLastRow();
var values = [];
for (var i = 0; i < end; i++) {
if (result[i][0] != "") {
values.push(result[i][0]);
}
}
return values;
}
Note:
About window.saveDia = function() {onOpen()};, unfortunately, I couldn't understand about what you want to do.
Reference:
Class google.script.run
I have some js code that has been imported from another file which has a variable in it I want to update in my HTML file. How can I update the variable without pasting the js code into my HTML file?
JS (script.js):
var link = "https://example.com"
var codeBlock = `...some html code... ${link} ...some more html code`;
document.getElementById("div").innerHTML = codeBlock
HTML:
<div id="div"></div>
<script src= "script.js"></script>
<script>
//I want to change this variable
var link = "https://anotherexample.com"
</script>
On line one of your code, you declare link and give it a value.
On line two, you use that value.
You can't change link later on and affect what happened when the value was read and used in the past.
If you want to change the final result, then it is the final result you have to change (i.e. you need to assign a new value to document.getElementById("div").innerHTML).
You are getting the value but not setting it to the variable that the HTML is showing.Is this you are looking for :
var updatedLink = document.getElementById("anotherlink").innerHTML;
var codeBlock = `...some html code... ${updatedLink} ...some more html code`;
document.getElementById("div").innerHTML = codeBlock
<div id="div"></div>
<div id="anotherlink" style="display:none"></div>
<script src= "script.js"></script>
<script>
var link = "https://anotherexample.com";
document.getElementById("anotherlink").innerHTML = link
</script>
Your script is working and the variable is being changed. If you console.log(link) after declaring it again, you'll see the variable has changed. If you're expecting the script to execute again, that won't happen without calling it again.
What you may want to try is iterating through the document looking for something to trigger that statement, for example, links in the document.
const links = document.querySelectorAll('a');
var href = [];
links.forEach(link => href.push(link.href));
var codeBlock = '';
href.forEach(link => {
if (link == "https://stacksnippets.net/anotherexample.com") {
codeBlock = `...some html code... ${link} ...some more html code`;
document.getElementById('div').innerHTML = codeBlock;
}
})
<div id="div">link</div>
Or without checking for a specific URL:
const links = document.querySelectorAll('a');
var href = [];
links.forEach(link => href.push(link.href));
var codeBlock = '';
href.forEach(link => {
codeBlock = `...some html code... ${link} ...some more html code`;
document.getElementById('div').innerHTML = codeBlock;
})
<div id="div">link</div>
Ok, so I am trying to make a function in google sheets that when the user selects a cell and then runs the function (currently trying to make), a sidebar getting all the synonyms of the word should appear. I am using https://words.bighugelabs.com/ to get the synonyms. So first I make the menu:
`function onOpen(e) {
var ui = SpreadsheetApp.getUi().createMenu("Sidebar")
.addItem("Get Synonym", 'showSidebar')
.addToUi();
}`
Then this is the showSidebar function:
function showSidebar() {
var html = HtmlService.createHtmlOutputFromFile("Test")
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(150)
.setTitle("My Sidebar");
SpreadsheetApp.getUi().showSidebar(html);
}
This is the html file:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function doSomething() {
var synonyms = google.script.run.getSynonym();
document.getElementById("synonyms").innerHTML = synonyms;
}
</script>
</head>
<body>
<div>
<span style="color:orange;">This is a test sidebar!</span>
<button onclick="doSomething()">Click Me!</button>
<div id="synonyms"></div>
</div>
</body>
</html>
And this is the getSynonym function:
function getSynonym() {
var word = SpreadsheetApp.getActiveRange().getValue();
var synonyms = [];
var response = UrlFetchApp.fetch("http://words.bighugelabs.com/api/2/{my_api_key}/" + word + "/json");
response = JSON.parse(response);
var synonyms = response.adjective.syn;
return synonyms;
}
But the variable synonyms which as an array of synonyms doesn't get returned to the doSomething function in the Html file.
What I want is that the sidebar should get a list of all the synonyms.
So basically I can't get the data from one function to another...and I want to know if this is the right way.
When calling server side functions using google.script.run you need to define a success handler, which will asynchronously receive your response.
See the examples on: https://developers.google.com/apps-script/guides/html/communication
function onSuccess(synonyms ) {
console.log(synonyms);
}
google.script.run.withSuccessHandler(onSuccess).doSomething();
How to retrieve a complete row from a spreadsheet based on a filter on an action such as a click of a button.
I read that GAS is server-side scripting and it is complex to gain access to a spreadsheet.
Is that so. Please guide me.
I have done till this:
$("#form-action")
.button()
.click(function() {
var ss = SpreadsheetApp.openById("");
var sheet = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(sheet.getSheetByName('Test'));
SpreadsheetApp.getActiveSheet().getRange("D1").setFormula('Query(A:C,"SELECT A,B,C WHERE B="' + "mydata'" + ',1)');
SpreadsheetApp.getActiveSheet().getRange("E:J").getValues();
});
Gaining access to the spreadsheet is not difficult at all. You have to remember that while Google Apps Script runs on Google servers, the client-side code (e.g. HTML and JavaScript code you use in your UI templates) will be sent to your browser for rendering, so you can't really mix the two and write jQuery code in GAS(.gs) files or vice versa.
To clarify, commands like
var ss = SpreadsheetApp.openById("");
must be kept in .gs files. To use client-side HTML and JavaScript, you must create separate HTML files in your project (go to File - New - HTML file). Here's more information on serving HTML in GAS https://developers.google.com/apps-script/guides/html/
Luckily, Google provides the API that allows you to communicate between client and server sides by calling 'google.script.run.' followed by the name of the function in '.gs' file.
Example function in '.gs' file
function addRow() {
var sheet = SpreadsheetApp.getActive()
.getSheets()[0];
sheet.appendRow(['Calling', 'server', 'function']);
}
In your HTML template file, here's how you would call this function
<script>
google.script.run.addRow();
</script>
Consider the example that is more relevant to your situation. In my spreadsheet, the QUERY formula changes dynamically based on the value entered by the user. The form with input field is displayed in the sidebar.
Project structure
Code for 'sidebar.html' is below. Note that using the 'name' attribute of the <input> element is mandatory. On form submit, the value of the attribute ('filterBy') will be transformed into propetry of the form object that we can reference in our server function to get user input.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
</script>
</head>
<body>
<form id="myForm">
<input type="text" name="filterBy">
<input type="submit" value="submit">
</form>
<table id="myTable"></table>
<script>
$('document').ready(function(){
var form = $('#myForm');
var table = $('#myTable');
var runner = google.script.run;
form.on('submit', function(event){
event.preventDefault(); //prevents <form> redirecting to another page on submit
table.empty(); // clear the table
runner.withSuccessHandler(function(array){ //this callback function will be invoked after the 'retriveValues()' function below
for (var i = 0; i < array.length; i++) {
var item = '<tr><td>' + array[i] +'</td></tr>';
table.append(item);
}
})
.retrieveValues(this); //the function that will be called first. Here, 'this' refers to the form element
});
});
</script>
</body>
</html>
Code in '.gs' file:
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheets()[0];
function onOpen() {
var ui = SpreadsheetApp.getUi();
var htmlOutput = HtmlService.createTemplateFromFile('sidebar')
.evaluate();
ui.showSidebar(htmlOutput);
}
function retrieveValues(req) {
var res = [];
var filterBy = req.filterBy; //getting the value of the input field.
sheet.getRange(1, 2, 1, 1)
.setFormula("QUERY(A1:A, \"SELECT A WHERE A > " + filterBy + "\")");
sheet.getRange(1, 2, sheet.getLastRow(), 1)
.getValues()
.map(function(value){
if (value[0] != "") res = res.concat(value[0]); // get only the values that are not empty strings.
});
return res;
}
Here's the result of entering the value and submitting the form. The server-side function returns the array of values greater than 5. The callback function that we passed as parameter to 'withSuccessHandler' then receives this array and populates the table in the sidebar.
Finally, I'm not sure why you are using the QUERY formula. Instead of modifying 'SELECT' statement, you could simply take the values from the target range an filter them in GAS.
I'm trying to learn Google's HTML Service UI service and am struggling to figure out how to update a dropdown list in a UI from data in a spreadsheet. I copied the following code from this Google Tutorial, which works fine. However, if I want to populate a dropdown using and to replace and below, it doesn't seem to work.
<p>List of things:</p>
<ul id="things">
<li>Loading...</li>
</ul>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(showThings)
.getLotsOfThings();
});
function showThings(things) {
var list = $('#things');
list.empty();
for (var i = 0; i < things.length; i++) {
list.append('<li>' + things[i] + '</li>');
}
}
</script>
The following Apps Script project files use Spreadsheet data to fill a drop-down select box in the UI. In the main Apps Script project file (default name is Code.gs), include:
function doGet(request) {
return HtmlService.createTemplateFromFile('DropDown')
.evaluate().setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
function getMenuListFromSheet() {
return SpreadsheetApp.openById(*SPREADSHEET_ID*).getSheets()[0]
.getRange(2,1,4,1).getValues();
}
You will need to replace *SPREADSHEET_ID* with the ID of the spreadsheet containing the data you want to use to fill the select box. This example takes the data in the first sheet's A2:A5 range as the data to use (defined in the getRange() function).
Note also that this example uses NATIVE sandbox mode, which is more forgiving than the default EMULATED mode.
This example also needs an HTML file in the Apps Script project(named 'DropDown.html' here):
<p>List of things:</p>
<ul id="things">
<li>Loading...</li>
</ul>
<select id="menu">
<option></option>
<option>Google Chrome</option>
<option>Firefox</option>
</select>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(showThings)
.getMenuListFromSheet();
google.script.run.withSuccessHandler(showMenu)
.getMenuListFromSheet();
});
function showThings(things) {
var list = $('#things');
list.empty();
for (var i = 0; i < things.length; i++) {
list.append('<li>' + things[i] + '</li>');
}
}
function showMenu(menuItems) {
var list = $('#menu');
list.find('option').remove(); // remove existing contents
for (var i = 0; i < menuItems.length; i++) {
list.append('<option>' + menuItems[i] + '</option>');
}
}
</script>
This HTML file consists of a single list and a single select box, both with default contents. When the page is loaded, the contents of both will be replaced with the contents provided by the getMenuListFromSheet() function, which draws its returned value from the spreadsheet.
You can create these Apps Script project files bound to a Spreadsheet container, and then publish them as a web app.