Re-worded objective:
I'm creating a web page using google apps script. I want to have multiple drop downs listed on the page. I know if I use <select><option>, I can create a list of hard coded options. What I would rather do is grab the options from a google sheet to display in the drop down, this way I can update it at anytime without modifying the HTML code.
The issue: While I was successful in creating a drop down selection containing Column A values from my sheet, I'm running into an issue where Apps Script will not let me create another drop down containing the values of Column B.
This is my sheet that contains names and dietary types. Each column contains the options for each drop down.
This is what it looks like on the front end. I'd like to have another drop down beside it that contains values from Column B (as seen above).
Here is my script:
var url = "google sheets URL";
function doGet(e){
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Staff");
var list = ws.getRange(1,1,ws.getRange("A1").getDataRegion().getLastRow(),1).getValues();
var tmp = HtmlService.createTemplateFromFile("index");
tmp.list = list.map(function(r){ return r[0]; });
return tmp.evaluate();
}
This is the HTML for my selection list:
<select id="app" class="browser-default">
<option disabled selected>Select a teammate!</option>
<? for(var i=0;i<list.length;i++){ ?>
<option><?= list[i]; ?></option>
<? } ?>
</select>
It functions correctly at this point but when trying to replicate it so I can grab another column in Google Sheets and use that as another selection list,
I get: Referenceerror: "list" is not defined.
This is the script that's causing me to get the error.
var url = "google sheets URL";
function doGet(e){
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Staff");
var list = ws.getRange(1,1,ws.getRange("A1").getDataRegion().getLastRow(),1).getValues();
var tmp = HtmlService.createTemplateFromFile("index");
tmp.list = list.map(function(r){ return r[0]; });
return tmp.evaluate();
}
function doGet(f){
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Variables");
var list2 = ws.getRange(1,1,ws.getRange("A1").getDataRegion().getLastRow(),1).getValues();
var tmp2 = HtmlService.createTemplateFromFile("index");
tmp2.list2 = list2.map(function(r){ return r[0]; });
return tmp2.evaluate();
}
Here's a simple example of getting multiple list from a dialog.
Load the code and run launchDialog(). You could also add a doGet() and use return HtmlService.createHtmlOutputFromFile('aq4');
Code.gs:
function getList(n) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet1');
var rg=sh.getRange(2,n,sh.getLastRow()-1,1);
return rg.getValues().map(function(r){return r[0]});
}
function launchDialog() {
var userInterface=HtmlService.createHtmlOutputFromFile('aq4');
SpreadsheetApp.getUi().showModelessDialog(userInterface, 'My List');
}
aq4.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<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>
<style>
input{margin:5px;}
td,th{border:1px solid black;}
</style>
<script>
$(function(){
google.script.run
.withSuccessHandler(function(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]);
}
})
.getList(1);
});
function getAnotherList() {
google.script.run
.withSuccessHandler(function(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]);
}
})
.getList(Math.floor(Math.random()*23));
}
console.log("My Code");
</script>
</head>
<body>
<select id="sel1"></select>
<input type="button" value="Get Another List" onClick="getAnotherList();" />
</body>
</html>
Here's my List Spreadsheet:
Related
i've have an html file with two textboxes
1.orders
1.amount
i want that when i type a number in the orders text box
i will get the value from another column in my Google Sheet in the same row that match to to this order
this is my Code.gs code its not working
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('page');
}
function getCost(oneCode){
var url = "https://docs.google.com/spreadsheets/d/1333t7lvECnmOcCnTE6gnn_RN1wrPckWpIETiPUjkUnU/edit#gid=0";
var ss = SpreadsheetApp.openUrl(url);
var ws = ss.getSheetByName("Sheet1");
var data = ws.getRange(1,1,ws.getLastRow(),2).getValues();
var ordersList = data.map(function(r){ return r[0]; });
var amountList = data.map(function(r){ return r[1]; });
var position = ordersLis.indexOf(oneCode);
if(position > -1){
return amountList[position];
} else {
return "not found";
}
}
========================
this the html code
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<script>
document.getElementById("one").addEventlistener("input",doThis);
function doThis(){
var oneCode = document.getElementById("one").value;
google.script.run.withSuccessHandler(updateAmount).getCost(oneCode);
}
function updateAmount(cost){
document.getElementById("two").value = cost;
}
</script>
<body>
<div>
<input id="one" type="text">
<label for="one">orders</label>
</div>
<div>
<input disabled id="two" type="text">
<label for="two">amount</label>
</div>
</body>
</html>
I would like to propose the following modification.
Modification points:
At HTML&Javascript side,
addEventlistener is addEventListener.
When your script is used, please modify document.getElementById("one").addEventListener("input",doThis); to as follows. Because when document.addEventListener("DOMContentLoaded", function) is not used, an error occurs at addEventListener.
document.addEventListener("DOMContentLoaded", function(){
document.getElementById("one").addEventListener("input",doThis);
});
When input is used as the event type, when the inputted text is 130, 1, 13 and 130 are sent. By this, google.script.run.withSuccessHandler(updateAmount).getCost(oneCode) is run 3 times. So I think that change might be suitable for this situation.
At Google Apps Script side,
At var ss = SpreadsheetApp.openUrl(url);, openUrl is openByUrl.
I think that in your script, var position = ordersLis.indexOf(oneCode); is var position = ordersList.indexOf(oneCode);.
In your script, oneCode of getCost(oneCode) is the string type.
When above points are reflected to your script, it becomes as follows.
Modified script:
HTML&Javascript side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<script>
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("one").addEventListener("change", doThis);
});
function doThis() {
var oneCode = document.getElementById("one").value;
google.script.run.withSuccessHandler(updateAmount).getCost(oneCode);
}
function updateAmount(cost) {
document.getElementById("two").value = cost;
}
</script>
<body>
<div>
<input id="one" type="text">
<label for="one">orders</label>
</div>
<div>
<input disabled id="two" type="text">
<label for="two">amount</label>
</div>
</body>
</html>
When <script>###</script> is bottom of HTML, I think that document.addEventListener("DOMContentLoaded", function() {}) is not required to be used.
Google Apps Script side:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('page');
}
function getCost(oneCode){
var url = "https://docs.google.com/spreadsheets/d/1333t7lvECnmOcCnTE6gnn_RN1wrPckWpIETiPUjkUnU/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Sheet1");
var data = ws.getRange(1,1,ws.getLastRow(),2).getValues();
var ordersList = data.map(function(r){ return r[0].toString(); });
var amountList = data.map(function(r){ return r[1].toString(); });
var position = ordersList.indexOf(oneCode);
if(position > -1){
return amountList[position];
}
return "not found";
}
Usage:
From your script, it seems that you are using Web Apps. When you use this script, please copy and paste the above scripts to the script editor, and please redeploy the Web Apps as new version. By this, the latest script is reflected to Web Apps. Please be careful this.
When the Web Apps is opened, please input a value to the input box and push the enter key or remove the focus from the input box. By this, addEventListener("change", doThis) is executed and doThis is run.
References:
addEventListener()
openByUrl(url)
Web Apps
I have a google sheet, I want to prompt a user to select ranges to get information from, store that into an array, and then create a chart in an html popup. I have read a bit about the google.script.run functionality, and understand that without the withSuccessHandler(HTMLFunction).FunctionToCall() syntax at the end, the HTML script moves onto the next line. I have a .gs file below, and an .html file, and I was able to get the graph to work when I just entered a static array in my .gs function. However, I seem to be struggling with how to return focus to the editor to get a range, and then to bring the HTML dialog box with the chart back up and get the right data to the function that plots the chart. I saw here that I could use the google.script.host to call the editor.focus() function so the user can now select cells, but I can't seem to get the focus back to the HTML popup without calling the HTML file all over again. Here is my .gs function:
function RetrieveData(){
var ss = SpreadsheetApp.getActive();
var sheets = ss.getSheets();
var s = sheets[1];
var UI = SpreadsheetApp.getUi();
var response = UI.prompt("Please enter the first cell in the category").getResponseText();
var ir = s.getRange(response);
var n= 0;
var stored = [];
stored.push(["Income Category", "Frequency"]);
while (ir.getValue()!= "") {
n = n +1;
ir = ir.offset(1, 0);
}
ir = ir.offset(-n,0)
for(i =0; i<n;i++) {
stored.push([ir.getValue(),ir.offset(n+2,0).getValue()]);
ir = ir.offset(1, 0);
}
return stored;
}
Here is my html that is within the body (Stack Overflow is a little strict, so I am not going to go through the trouble of showing all the HTML; this is just within the body and it is what is communicating with the .gs file):
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(getdata);
function getdata() {
google.script.run.withSuccessHandler(drawChart).RetrieveData();
google.script.host.editor.focus();
}
function drawChart(stored) {
//This apparently shows a log of the object
//console.log(stored);
var data = new google.visualization.arrayToDataTable(stored);
console.log(data);
var options = {'title':'Income',
'width':400,
'height':300,
'is3d':true};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, options);
google.script.run.withSuccessHandler(drawChart).RetrieveData();
}
One last thing I tried was to call the
SpreadsheetApp.getUi().showModalDialog(html, "Title") function one more time, but without calling the html file all over again, and creating an endless loop, I don't seem to have a way to do that. Any idea how to accomplish this?
Here's a simple example of picking a range with a modeless dialog. With just a few extra features thrown in for good measure.
Code.gs:
function selRange()//run this to get everything started. A dialog will be displayed that instructs you to select a range.
{
var output=HtmlService.createHtmlOutputFromFile('pickRange').setWidth(300).setHeight(200).setTitle('Select A Range');
SpreadsheetApp.getUi().showModelessDialog(output, 'Range Selector');
}
function selCurRng()
{
var sso=SpreadsheetApp.getActive();
var sh0=sso.getActiveSheet();
var rg0=sh0.getActiveRange();
var rng0A1=rg0.getA1Notation();
rg0.setBackground('#777700');
return rng0A1;
}
function clrRange(range)
{
var sso=SpreadsheetApp.getActive();
var sh0=sso.getActiveSheet();
var rg0=sh0.getRange(range);
rg0.setBackground('#ffffff');
}
pickRange.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var grange='';
function selectRange()
{
$('#btn1').prop('disabled',true);
$('#btn2').prop('disabled',false);
google.script.run
.withSuccessHandler(setResponse)
.selCurRng();
}
function setResponse(r)
{
grange=r;
var msg='You have select the range ' + r;
$('#instr').css('display','none');
$('#rsp').text(msg);
}
function clearAndClose()
{
google.script.run.clrRange(grange);
google.script.host.close();
}
console.log('My Code');
</script>
</head>
<body>
<div id="rsp"></div>
<div id="instr">Please select your desired range.</div>
<input type="button" id="btn1" value="Range Selected" onClick="selectRange();" />
<br /><input type="button" id="btn2" value="close" onClick="clearAndClose();"; disabled="true" />
</body>
</html>
I'm creating a sidebar in a Google sheet. I have no problem getting it to appear with select lists. I'm trying to populate the select lists based on a range in one of the sheets. I've tried numerous suggestions from stackoverflow and I've read Google's documentation for the HTML Service many times. I still seem to be missing something. From my testing, it appears that the google.script.run call to the server is never executed. Here is my code.gs file:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Schedule')
.addItem('New schedule', 'newSchedule')
.addItem('Edit start date', 'newDate')
.addSeparator()
.addItem('Insert names', 'openInsert')
.addToUi();
}
function openInsert() {
var html = HtmlService.createHtmlOutputFromFile('Insert')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('Insert Names')
.setWidth(300);
SpreadsheetApp.getUi()
.showSidebar(html);
}
function getNames() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Publishers");
var names = sheet.getRange(2, 1, sheet.getLastRow(),1).getValues();
return names;
}
Here is my Insert.html file:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<script>
function returnedNames(names) {
var selectList = new Array("publisher1","publisher2","publisher3");
for (sel in selectList) {
var dropDown = document.getElementById(sel);
for (i = 0; i < names.length; i++) {
var opt = document.createElement("option");
opt.text = names[i][0];
opt.values = names[i][0];
dropDown.options.add(opt);
}
}
}
google.script.run.withSuccessHandler(returnedNames).getNames();
</script>
</head>
<body>
<div class="block form-group">
<label for="publisher1">First publisher</label>
<select id="publisher1"> </select>
<label for="publisher2">Second publisher</label>
<select id="publisher2"> </select>
<label for="publisher3">Third publisher (optional)</label>
<select id="publisher3"> </select>
</div>
</body>
</html>
I believe your server function is being called before your document is actually ready to be worked on. I'd imagine that if you checked the browser console window with developer tools, you'd see an error pop up.
Since you essentially want these populated onload, add a load event to the body tag. Have that event call your server function. If this doesn't work use a combination of Logger.log on the server side and console.log on the client side through out your sequence of code and see what you get and what path your code follows.
I have been trying to read data from file ans display it into some kind of listBov in html page by using java script.
I have been trying many cources, but there is no working code (I've trying on IE, Firefox and Chrome)
There is one of the attempt to do that, but it also without success:
File 1:
indexTST.html
<html>
<head>
<script language="JavaScript" type="text/javascript" src="java.js">
</script>
<body>
<td><form name="listBox" action="javascript:void 0;">
<select name="listBox" size="10">
<option>Select your home location</option>
<option>unknown</option>
</select>
</form>
<script type="text/javascript" language="JavaScript">
loadData();
with (document.listBox) {
listBox.options.length=0;
for (var i=0; i<Table.length; i++) {
listBox.options[listBox.options.length]=new Option(Table[i]);
}
}
reset1();
</script>
</body>
</html>
File 2:
java.js
var Table = [];
var txtFile;
function loadData2() {
Table = [];
lines = txtFile.responseText.split("\n");
for (i = 0; i < lines.length-1; i++) {
Table.push(lines[i]);
}
}
function loadData() {
var f = "dataFile.txt";
alert('01');
txtFile.open("GET", f, false);
alert('02');
txtFile.onreadystatechange=loadData2;
txtFile.send(null);
}
File 4:
dataFile.txt
Data 01
Data 02
Data 03
end
What I'm trying to achieve is:
Read text data from file (between 1 and 5 000 lines) and the file is on the server side (not local browser side)
Display it into some kind of listBox on web page
It's need to be "clickable/selectable" - because when user select i.e. item 5 - this one item need to be save into "saved.txt"
Thanks for help
Read a file and appends its contents by line to a list, and log the selected options. I hope it helps.
<!DOCTYPE html>
<html>
<body>
<h3>Read file</h3>
<input id="file-input" type="file" id="myFile">
<select multiple id="list"></select>
<button onclick="logSelected()">Log selected</button>
<script>
function readSingleFile(evt) {
//Retrieve the first (and only!) File from the FileList object
var f = evt.target.files[0];
if (f) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
console.log(contents);
var select = document.getElementById('list');
var lines = contents.split('\n');
lines.map(function(line){
var docLine = document.createElement('option');
docLine.innerHTML = line;
select.appendChild(docLine);
});
}
r.readAsText(f);
} else {
alert("Failed to load file");
}
}
document.getElementById('file-input').addEventListener('change', readSingleFile, false);
function logSelected(){
var select = document.getElementById("list");
var selected = [];
for (var i = 0; i < select.length; i++) {
if (select.options[i].selected) selected.push(select.options[i].value);
}
console.log(selected);
};
</script>
</body>
</html>
I am currently researching the possibility to grabbing data from the Tableau report(s) via the JavaScript API but the closet I can get to grabbing values from a graph after filtering is selecting the value via the selectSingleValue() method.
For example: JavaScript API Tutorial
In the API tutorial tab called 'Select'. One of the examples selects the row "Marcao Sao, China". Is it possible to extract that numerical value of $52.0k ?
I have tried looking into the Objects returned (via FireBug) but I cannot seem to locate the right object. My recent location was in getActiveSheets().
Any help would be appreciated.
In the JavaScript API tutorial tab 'Events' it shows you how to add an event listener to return the selected marks. You can then loop through the marks to get the values you want.
Copy the below code block into a file, save as html and open in your favourite web browser (tested on ie11).
<html>
<head>
<meta charset="utf-8">
<title>Tableau 8 Javascrip API</title>
<script type="text/javascript" src="http://public.tableausoftware.com/javascripts/api/tableau_v8.js"></script>
<script type="text/javascript">
/////////////////////
// Global variables
var viz, workbook, activeSheet
// function called by viz on marks being selected in the workbook
function onMarksSelection(marksEvent) {
return marksEvent.getMarksAsync().then(reportSelectedMarks);
}
function reportSelectedMarks(marks) {
for (var markIndex = 0; markIndex < marks.length; markIndex++) {
var pairs = marks[markIndex].getPairs();
for (var pairIndex = 0; pairIndex < pairs.length; pairIndex++) {
var pair = pairs[pairIndex];
if (pair.fieldName == "AVG(F: GDP per capita (curr $))") {
alert("You selected a country with an avg GPD per capita of " + pair.formattedValue);
}
}
}
}
// Initialise the viz to hold the workbook
function initializeViz(){
var placeholderDiv = document.getElementById("tableauViz");
var url = "http://public.tableausoftware.com/views/WorldIndicators/GDPpercapita?Region=";
var options = {
width: "800px", //width: placeholderDiv.offsetWidth,
height: "400px", //height: placeholderDiv.offsetHeight,
hideTabs: true,
hideToolbar: true,
onFirstInteractive: function () {
workbook = viz.getWorkbook();
activeSheet = workbook.getActiveSheet();
}
};
viz = new tableauSoftware.Viz(placeholderDiv, url, options);
// Add event listener
viz.addEventListener(tableauSoftware.TableauEventName.MARKS_SELECTION, onMarksSelection);
}
</script>
</head>
<body>
<!-- Tableau view goes here -->
<div id="tableauViz" style="height:1200px; width:1200px"\></div>
<script type='text/javascript'>
//Initialize the viz after the div is created
initializeViz();
</script>
</body>
</html>