Swtich from UiApp to HtmlService [duplicate] - google-apps-script

This question already has answers here:
UiApp has been deprecated. Please use HtmlService instead
(1 answer)
Uploading file to spreadsheet shows "UiApp has been deprecated. Please use HtmlServices instead"
(1 answer)
Closed 6 months ago.
I'm not a programmer or anything so please excuse any mistake.
I'm trying to use a code in Apps Script to facilitate data entry on a google sheets that I found online. The problem is the original creator used UiApp which has been deprecated.
I've been scouring the internet for anyway of making the change to Html but with no result.
I was hoping one of you could help me out!
Thank you
function doGet() {
var sheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1J_Fi7-hJuZkA2UftqM1Q-SG5NWxdQZkhLGjLIlVowTc/edit?usp=sharing'); //the spreadsheets url in which you want to change
var app = UiApp.createApplication(); //creates the application
var ss = sheet.getSheets()[0]; //gets the first sheet in the spreadsheet
var myPanel = app.createVerticalPanel(); //creates a vertical panel
var scroll = app.createScrollPanel().setPixelSize(200, 600); //creates a scrolling panel with the dimensions in its parameter
var panel3 = app.createVerticalPanel(); //creates a vertical panel
var panel4 = app.createVerticalPanel(); //creates a vertical panel
var panel = app.createVerticalPanel(); //creates a vertical panel
var panel2 = app.createAbsolutePanel().setSize('100%','100%').setId('absPanel'); //creates an absolute panel that covers the whole application
var periodKey = sheet.getSheetByName('Periods');//gets the sheet titled periods
var periodKeyValues = periodKey.getDataRange().getValues();//gets the values in the sheet
var guildKey = sheet.getSheetByName('Guilds');//gets the sheet titled Guilds
var guildKeyValues = guildKey.getDataRange().getValues();//gets the values in that sheet

Here is a simple example of how to build a table using HTML Service using a template and then using google.script.run to send new data to the spreadsheet.
My spreadsheet Sheet1 looks like this.
Code.gs
function doGet() {
try {
let html = HtmlService.createTemplateFromFile("HTML_Test");
let spread = SpreadsheetApp.openById("1uqq7UeFgYBM_Onzcq0o9ZuHLcmMEotN8hlmo83Ipt0A");
let sheet = spread.getSheetByName("Sheet1");
let data = sheet.getDataRange().getDisplayValues(); // data includes dates
html.data = data;
return html.evaluate();
}
catch(err) {
Logger.log(err);
}
}
function addRow(values) {
try {
let spread = SpreadsheetApp.openById("1..your id here...A");
let sheet = spread.getSheetByName("Sheet1");
let row = [ values.id, values.name, values.date ];
sheet.appendRow(row);
return row;
}
catch(err) {
Logger.log(err);
}
}
HTML_Test
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
table, th, td {
width: 10%;
border: 1px solid black;
}
</style>
</head>
<body>
<div id="inputFields">
ID:<input id="idField" type="text"><br>
Name:<input id="nameField" type="text"><br>
Date:<input id="dateField" type="text"><br>
<input id="submitButton" type="button" value="Submit" onclick="submitOnClick()">
</div>
<div id="tableDiv">
<table id="myTable">
<? for( var i=0; i<data.length; i++ ) { ?>
<tr>
<? for( var j=0; j<data[0].length; j++ ) { ?>
<td>
<?= data[i][j] ?>
</td>
<? } ?>
</tr>
<? } ?>
</table>
</div>
<script>
function submitOnClick() {
try {
let id = document.getElementById("idField").value;
let name = document.getElementById("nameField").value;
let date = document.getElementById("dateField").value;
// make sure its a valid date
if( isNaN(Date.parse(date)) ) throw "invalid date";
google.script.run.withSuccessHandler(
function(values) {
let table = document.getElementById("myTable");
let row = table.insertRow(-1);
for( let i=0; i<values.length; i++ ) {
let cell = row.insertCell(i);
cell.innerHTML = values[i];
}
}
).addRow({ id: id, name: name, date: date });
}
catch(err) {
alert(err);
}
}
</script>
</body>
</html>
My form looks like this
References:
HTML Service
google.script.run
Javascript and HTML DOM

Related

Having trouble creating an HTML drop down list from Google Sheets

New to Google scripts. Trying to create a form with a dropdown list populated with one of the google sheets.
I found a couple of examples of this on the web and tried to create a dropdown list on a sidebar from Sheets. the spreadsheet has a tab named 'CARS'. Separately, I ran the Code.gs which generates the values for the dropdown list and it is working.
However, the sidebar does not show the dropdown list. Here are the two files (HTML and gs) I am using. Thanks.
Code.gs
function getList() {
console.log('cars')
var ss = SpreadsheetApp.getActiveSpreadsheet();
var carSheet = ss.getSheetByName("CARS");
var LastRow = carSheet.getLastRow();
console.log(LastRow)
return carSheet.getRange(2,1,LastRow - 1, 2).getValues();
}
function startForm() {
var form = HtmlService.createHtmlOutputFromFile('dropdownList');
SpreadsheetApp.getUi().showSidebar(form);
}
function addMenu() {
var menu = SpreadsheetApp.getUi().createMenu('Custom');
menu.addItem('Dropdown List', 'startForm');
menu.addToUi();
}
function onOpen(e)
{
addMenu();
}
dropdownList.html
<!DOCTYPE html>
<script>
function loadCars() {
google.script.run.withSuccessHandler(function(ar))
console.log('in loadcars')
{
var carsSelect = document.getElementById("cars");
console.log(ar)
let option = document.createElement("option");
option.value = "";
option.text = "";
carsSelect.appendChild(option);
ar.forEach(function(item,index)
{
let option = document.createElement("option");
option.value = item[1];
option.text = item[0];
carsSelect.appendChild(option);
});
}).getList();
};
function onSelect()
{
var carID = document.getElementById("cars").value;
document.getElementById("carValue").innerHTML = carID;
};
</script>
<html>
<head>
<h1>something</h1>
<base target="_top">
</head>
<body>
<select id="cars" onChange="onSelect()" ></select><br>
<span id>"carValue"</span>
<script>loadCars();</script>
</body>
</html>
Upon further review of the code in dropdowList.html found two errors. I had typed ="carValue" instead of <span id = "carValue>. The other error was
google.script.run.withSuccessHandler(function(ar))
instead of
google.script.run.withSuccessHandler(function(ar)
essentially causing the function not to run properly.
Sorry for the trouble

Write data array from a google app script function to a HTML paragraph <p> tag

I have this google test sheet with dummy data that I have created for testing purposes
https://docs.google.com/spreadsheets/d/1Hxjr1ai6KWWJyyQLPJ2GRWYgQftyBxJmiKEu25Co2aQ/edit#gid=0
Crypto Data Image
By using google app script I have created a google web app with a HTML drop down box (select in HTML) that gets data from the above google sheet.
https://script.google.com/macros/s/AKfycbzYDDLg6YDNLBo-3jKQpcedU9jLJbxbOUDMh5YayKtVaurN2COq/exec
The google web app successfully displays the users selection from the drop down box in a HTML paragraph tag but the web app fails to display the data array for the selected cryptocurrency. The error message is "undefined".
I have just been doing this google app script stuff for a couple of weeks and I have a hard time understanding why the user selected array with data is not displayed on the HTML page.
My next step will be to try to plot the data the user selects from the HTML drop down box but before I can do that I need to visually confirm that the data is actually there.
If I select nano in the dropdown box this the data I get from the google apps script Logger.log:
[19-02-22 12:02:15:237 PST] The number of columns in sheet = 5
[19-02-22 12:02:15:238 PST] Crypto currencies in sheet = Bitcoin,Ethereum,Nano,Status,,,,,,,,,,,,,,,,,,,,
[19-02-22 12:02:15:241 PST] Dropdown box selection = Nano
[19-02-22 12:02:15:244 PST] Data to plot =0.9,0.8,0.7,0.8,
That tells me that the google app script is working but what is not working is the display of the data in the HTML paragraph tag on the website.
Code.gs
function getSelectList()
{
// puts crypto currency names in dropdown box on website
var ss = SpreadsheetApp.openById("1Hxjr1ai6KWWJyyQLPJ2GRWYgQftyBxJmiKEu25Co2aQ");
var sheet = ss.getSheetByName("Sheet1");
var lastRow = sheet.getLastRow();
var myRange = sheet.getRange("A2:A" + lastRow);
var data = myRange.getValues();
return data;
}
function Selection(crypto_name)
{
var ss = SpreadsheetApp.openById("1Hxjr1ai6KWWJyyQLPJ2GRWYgQftyBxJmiKEu25Co2aQ");
var sheet = ss.getSheetByName("Sheet1");
var name = sheet.getRange('A2:A101').getValues();
var Nc = sheet.getLastColumn();
Logger.log("The number of columns in sheet = " + Nc);
Logger.log("Crypto currencies in sheet = " + [name]);
Logger.log("Dropdown box selection = " + crypto_name);
for (i = 0; i < name.length; i++)
{
if(name[i]== crypto_name)
{
var TS = sheet.getRange(i+2,2,1,Nc).getValues();
Logger.log("Data to plot =" + [TS]);
}
}
return TS ;
}
function doGet()
{
return HtmlService.createHtmlOutputFromFile("Web");
}
Web.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<select id="MyBox" onchange="GetMyBox(this)"> </select>
<script>
(function()
{
google.script.run.withSuccessHandler( function (selectList)
{
var select = document.getElementById("MyBox");
for( var i=0; i<selectList.length; i++ )
{
var option = document.createElement("option");
option.text = selectList[i][0];
select.add(option);
}
}
).getSelectList();
}());
function GetMyBox(sel)
{
var crypto_name = sel.value;
document.getElementById("demo1").innerHTML = crypto_name;
var data = google.script.run.Selection(crypto_name);
document.getElementById("demo2").innerHTML = data;
}
</script>
<p id="demo1"></p>
<p id="demo2"></p>
</body>
</html>
This isn't intended to be a complete answer I just took your code and reformatted it a bit based upon what I think you're trying to accomplish. I didn't look at your code precisely but I'm pretty sure you still have some debugging to do.
In the html it looked like you want to use the JQuery ready function so I added some JQuery references to the head. If that wasn't your plan then you might want to change to window.onload.
html:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<select id="MyBox" onchange="GetMyBox(this)"> </select>
<script>
$(function() {
google.script.run
.withSuccessHandler(selectList)//You can just put the name of the function in this way
.getSelectList();
});
function GetMyBox(sel) {
var crypto_name = sel.value;
google.script.run
.withSuccessHandler(function(data){//you put an anonymous function this way
document.getElementById("demo2").innerHTML = data;
}
.Selection(crypto_name);
}
function selectList(data){
var select = document.getElementById("MyBox");
for( var i=0; i<data.length; i++ ) {
var option = document.createElement("option");
option.text = data[i][0];
select.add(option);
}
</script>
<p id="demo1"></p>
<p id="demo2"></p>
</body>
</html>
Google Script:
function getSelectList() {
// puts crypto currency names in dropdown box on website
var ss = SpreadsheetApp.openById("1Hxjr1ai6KWWJyyQLPJ2GRWYgQftyBxJmiKEu25Co2aQ");
var sheet = ss.getSheetByName("Sheet1");
var lastRow = sheet.getLastRow();
var myRange = sheet.getRange("A2:A" + lastRow);
var data = myRange.getValues();
return data;//this is a 2d array it might be what you want for select options
}
function Selection(crypto_name) {
var ss = SpreadsheetApp.openById("1Hxjr1ai6KWWJyyQLPJ2GRWYgQftyBxJmiKEu25Co2aQ");
var sheet = ss.getSheetByName("Sheet1");
var name = sheet.getRange('A2:A101').getValues();
var Nc = sheet.getLastColumn();
Logger.log("The number of columns in sheet = " + Nc);
Logger.log("Crypto currencies in sheet = " + [name]);
Logger.log("Dropdown box selection = " + crypto_name);
for (i = 0; i < name.length; i++) {
if(name[i]== crypto_name) {
var TS = sheet.getRange(i+2,2,1,Nc).getValues();
Logger.log("Data to plot =" + [TS]);
}
}
return TS ; //this is a 2d array so it's not ready for html yet
}
After spending some time on the problem I figured it out. I will therfore answer my own question since no one is willing to provide a good answer to the question. I think it is important that a working solution to the problem is clearly presented so that anyone in the furure can easily find a solution to a similar question.
function GetMyBox(sel)
{
var crypto_name = sel.value;
document.getElementById("Tag1").innerHTML = crypto_name;
google.script.run.withSuccessHandler(callback).Selection(crypto_name);
}
function callback(whatToWrite)
{
document.getElementById("Tag2").innerHTML = whatToWrite;
}
</script>
<p id="Tag1"></p>
<p id="Tag2"></p>

How to Populate Google Sheet Cell with Selected Value from HTML UI?

I have created an HTML UI from a Google Sheet file I am working with. The UI pulls a list of vendors from my Vendor Database tab, allowing a user to select which vendor they'd like to place an order with from the HTML UI. Upon click of the Save button in the HTML UI, though, I'd like the file to populate cell B12 of the POTemplate tab with the user's selection, but am unsure how to do this. Right now, I have taken the following steps to make this happen, but with limited success:
APPS SCRIPT
This populates the HTML drop down list with vendor names from our Vendor Database tab in the active file:
function getVendors() {
var active = SpreadsheetApp.getActive();
var sheet = active.getSheetByName("Vendor Database");
var lastRow = sheet.getLastRow();
var myRange = sheet.getRange("A2:A" + lastRow);
var data = myRange.getValues();
var optionsHTML = "";
for (var i = 0; i < data.length; i+=1) {
optionsHTML += '<option>' + data[i][0] + '</option>';
};
return optionsHTML;
This attempts to grab the vendor selected in the HTML UI and populate the preferred cell in our POTemplate tab, B12:
function save(formObj) {
var vendor = formObj.vendor;
var app = SpreadsheetApp;
var orderSheet = app.getActiveSpreadsheet().getSheetByName("POTemplate");
orderSheet.getRange(B12).setValue(vendor);
}
HTML Code
<html>
<head>
</head>
<body>
<form>
<div>
<select id="vendor">
<?!= getVendors(); ?>
</select>
<select>
<?!= getATTN(); ?>
</select>
</div>
</form>
<input type="button" value="Save PO" class="button button2"
onClick="google.script.run.save(this.parentNode)" />
</body>
</html>
You can also do it like this:
code.gs:
function getSelectOptions() {
var data = SpreadsheetApp.getActive().getSheetByName('Vender Database').getDataRange().getValues();
var options = [];
//the loop skips the first line
for (var i = 1; i < data.length; i++) {
options.push(data[i][0]);
}
return options;
}
//for the webapp
function doGet()
{
var output=HtmlService.createHtmlOutputFromFile('test');
return output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
//for a dialog
function showDialog(){
var ui=HtmlService.createHtmlOutputFromFile('test');
SpreadsheetApp.getUi().showModelessDialog(ui, 'Get Options');
}
test.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function() {
google.script.run
.withSuccessHandler(updateSelect)
.getSelectOptions();//this updates the select options everytime you load the page.
});
function updateSelect(vA){
var select = document.getElementById("sel1");
select.options.length = 0;
for(var i=0;i<vA.length;i++)
{
select.options[i] = new Option(vA[i],vA[i]);
}
}
</script>
</head>
<body>
<select id="sel1"></select>
</body>
</html>
Saving the Selected Value in a Sheet
additional gs:
function savSelected(selected){
SpreadsheetApp.getActive().getSheetByName("POTemplate").getRange('B12').setValue(selected);
}
additional script function:
function savSelect(){
var selected=$('#sel1').val();
google.script.run.savSelected(selected);
}
additional html:
<select id="sel1" onChange="savSelect();"></select>
In your save() function, you need to surround "B12" in quotes.
function save(formObj) {
var vendor = formObj.vendor;
var app = SpreadsheetApp;
var orderSheet = app.getActiveSpreadsheet().getSheetByName("POTemplate");
orderSheet.getRange("B12").setValue(vendor);
}
In your HTML, you should not surround the google.script.run in quotes. Moreover, create a new function to make your life easier. You can modify the submitFormData() function in the HTML to include any other data that you might need to return.
<input type="button" value="Save PO" class="button button2"
onClick=submitFormData() />
<script>
function submitFormData() {
var vendor = document.getElementById("vendor").value;
var formObj = {};
formObj["vendor"] = vendor;
google.script.run.save(formObj);
}
</script>
(The getATTN() function wasn't provided, so I removed that from the HTML when testing this.)

Parse Html using Google App Script

I am trying to parse html using this script in Google app script
function parse() {
var html = UrlFetchApp.fetch('http://www.merriam-webster.com/').getContentText();
var doc = XmlService.parse(html);
var html = doc.getRootElement();
var element = getElementsByID(html, 'xx');
return element;
}
function getElementById(element, idToFind) {
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null) {
var id = elt.getAttribute('id');
if( id !=null && id.getValue()== idToFind) return elt;
}
}
}
But it says:
Error on line 27: Element type "scr" must be followed by either attribute specifications, ">" or "/>". (line 4, file "")
I am trying to parse html and then use getElementById function above.
any ideas?
I found that the best way to parse html in google apps is to avoid using XmlService.parse or Xml.parse. XmlService.parse doesn't work well with bad html code from certain websites.
Here a basic example on how you can parse any website easily without using XmlService.parse or Xml.parse. In this example, i am retrieving a list of president from "wikipedia.org/wiki/President_of_the_United_States"
whit a regular javascript document.getElementsByTagName(), and pasting the values into my google spreadsheet.
1- Create a new Google Sheet;
2- Click the menu Tools > Script editor... to open a new tab with the code editor window and copy the following code into your Code.gs:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu("Parse Menu")
.addItem("Parse", "parserMenuItem")
.addToUi();
}
function parserMenuItem() {
var sideBar = HtmlService.createHtmlOutputFromFile("test");
SpreadsheetApp.getUi().showSidebar(sideBar);
}
function getUrlData(url) {
var doc = UrlFetchApp.fetch(url).getContentText()
return doc
}
function writeToSpreadSheet(data) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var row=1
for (var i = 0; i < data.length; i++) {
var x = data[i];
var range = sheet.getRange(row, 1)
range.setValue(x);
var row = row+1
}
}
3- Add an HTML file to your Apps Script project. Open the Script Editor and choose File > New > Html File, and name it 'test'.Then copy the following code into your test.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input id= "mButon" type="button" value="Click here to get list"
onclick="parse()">
<div hidden id="mOutput"></div>
</body>
<script>
window.onload = onOpen;
function onOpen() {
var url = "https://en.wikipedia.org/wiki/President_of_the_United_States"
google.script.run.withSuccessHandler(writeHtmlOutput).getUrlData(url)
document.getElementById("mButon").style.visibility = "visible";
}
function writeHtmlOutput(x) {
document.getElementById('mOutput').innerHTML = x;
}
function parse() {
var list = document.getElementsByTagName("area");
var data = [];
for (var i = 0; i < list.length; i++) {
var x = list[i];
data.push(x.getAttribute("title"))
}
google.script.run.writeToSpreadSheet(data);
}
</script>
</html>
4- Save your gs and html files and Go back to your spreadsheet. Reload your Spreadsheet. Click on "Parse Menu" - "Parse". Then click on "Click here to get list" in the sidebar.
To parse the HTML you'll have to sanitize it, your page has a script tag that's written with Javascript as a String, more specifically:
document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');})
XML parser doesn't understand Javascript code, obviously, so you'll have to sanitize this manually, not a simple thing to do, you can however build a simple RegEx selector, as:
function getElementsByID(element, idToFind) {
var regId = new RegExp( '(<[^<]*id=[\'"]'+ idToFind +'[\'"][^>]*)' );
var result = regId.exec( element );
return result[1] + '>';
}
function parse() {
var html = UrlFetchApp.fetch('http://www.merriam-webster.com/').getContentText();
var element = getElementsByID(html, 'search_box_terms');
return element; // "<input id="search_box_terms" name="query" type="text" placeholder="I'm searching for ..." value="" />"
}
This will return the string of the element the ID you provide. This of course is a simple RegEx and won't work in ALL cases, but will do pretty well for the most of them.

Get an array of the sheets in a spreadsheet and list them?

I am trying to create a dynamically dependent dropdown, and for this I would like to have some layers of dependencies: first you choose between sheets, then between columns, and then between rows. I have a script now running in a Templated HTML file in Google Apps Script, which looks like this:
<?
var sheet = SpreadsheetApp.openById("1c7IwmyBrbNq5xwzo-7EyFewCx31WpfP4EzLpkHawffI").getSheetByName("test");
var lastRow = sheet.getLastRow();
var categoryRange = sheet.getRange("C2:C"+lastRow);
var category = categoryRange.getValues();
?>
Category: <select name="category">
<? for (var i = 0; i < category.length; ++i) { ?>
<option><?!= category[i] ?></option>
<? } ?>
</select>
<br/>
What I am trying to do now is to get an array or a list of some sort of all the sheets in a given spreadsheet, and then list them in a dropdown, with the names of the sheets.
From there I will have to find a way to make the dependencies, but then the selected sheet in the dropdown would set the sheet for the next dropdown or something?
To use in HTML the best practice is to load the page, run a function that return the info you need, and from that construct the HTML, here the sever side function:
function getSheetsNames(){
var sheetsName = [];
var sheets = ss.getSheets();
for( var i = 0; i < sheets.length; i++ ){
sheetsName .push(sheets[i].getName() )
};
return sheetsName;
}
If need help calling the server side function from HTML read best practices:
https://developers.google.com/apps-script/guides/html/best-practices#load_data_asynchronously_not_in_templates
Okay with great help from the user Kriggs the solution to getting sheets pushing them to a list of some sorts is as follows:
Page.html
<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)
.getSheetsNames();
});
function showThings(sheetsName) {
var list = $('#things');
list.empty();
for (var i = 0; i < sheetsName.length; i++) {
list.append('<li>' + sheetsName[i] + '</li>');
}
}
</script>
<?!= include('JavaScript'); ?>
JavaScript.html
<script>
window.addEventListener('load', function() {
console.log('Page is loaded');
});
</script>
Code.gs
function doGet(request) {
return HtmlService.createTemplateFromFile('Page')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function getSheetsNames(){
var ss = SpreadsheetApp.openById("Spreadsheet ID here");
var sheetsName = [];
var sheets = ss.getSheets();
for( var i = 0; i < sheets.length; i++ ){
sheetsName .push(sheets[i].getName() )
};
return sheetsName;
}
All of the above together will generate Page.html where a list, of all the sheets in your spreadsheet, will be created. This was really useful for me, hope everyone can use this. I will continue to work out how to do the dependent dropwdown :)