Display image in google sheet sidebar after dropdown selection - html

I am working on some small project using google sheet sidebar. My sidebar already has a dropdown which options are created based on the values of the specified cells in the spreadsheet. I am wondering whether it is even technically possibile to display image in sidebar after selection of the dropdown option. I would like to display image as a preview in sidebar just after I choose option from the dropdown but before I click "Add image to the spreasheet" button. So for example if I select "Banana" in the dropdown, the image of the banana will be displayed in the sidebar, just below dropdown so that before I send it to the spreadsheet by clicking the button I can see what image I will be sending. I know there is an option to display images in selection options of the dropdown, next to the text, but this is not what I am looking for. I am not a programmer so please let me know if I can explain anything better.
I was already trying with some HTML codes found in web but nothing really works. I am not sure whether I should use some conditional statement in HTML code.
This is how the code looks right now.
GS:
function loadform() {
var html = HtmlService
.createTemplateFromFile('ShowThefruit');
html.dynamicdropdown = SpreadsheetApp.getActiveSheet().getRange("A1:A5").getValues();
html = html.evaluate()
.setTitle('Show image of the fruit')
.setWidth(8000);
SpreadsheetApp.getUi().showSidebar(html);
}
HTML
<body bgcolor="#046ED2">
<font face="arial" color="white">
<b>Choose an object.</b><br><br>
<!-- Create input fields to accept values from the user -->
Object:<br>
<select id="Object">
<? for (let i in dynamicdropdown) { ?>
<option value="<?=dynamicdropdown[i]?>"><?=dynamicdropdown[i]?></option>
<? } ?>
</select>
<br>
<br>
<br>
PREVIEW OF THE IMAGE HERE
<br>
<br>
<br>
<button class="bnt btn-primary" id="mainButton" >Add image to the spreasheet</button>
Image will come from URL, so basically I would like to add below code to HTML but with condition of "Banana" value being selected from the dynamic dropdown.
<img src="URL OF BANANA PICTURE" width="50" height="60";>
Will really appreciate any help.

Try
code gs
function onOpen(e) {
  SpreadsheetApp.getUi()
.createMenu('⇩ M E N U ⇩')
.addItem('Open ...', 'loadform')
.addToUi();
}
function loadform(){
var ui = SpreadsheetApp.getUi();
var html = HtmlService
.createTemplateFromFile("index")
.evaluate();
html.setTitle("Show image of the ...");
ui.showSidebar(html);
}
function dynamicdropdown() {
return SpreadsheetApp.getActiveSheet().getRange("A1:B5").getValues()
}
code html
<!DOCTYPE html>
<html>
<head></head>
<body bgcolor="#046ED2">
<script>
<?
var data = dynamicdropdown();
?>
</script>
<? var data = dynamicdropdown(); ?>
<form>
<select name="img" onchange="choose(this);" font face="arial" color="white">
<option value="" disabled selected >Selectionner ...</option>
<? for (var i = 0; i < data.length; i++) { ?>
<option value="<?= data[i][1] ?>" ><?= data[i][0] ?></option>
<? } ?>
</select>
</form>
<br/>
<div id="myImg"></div>
<script>
function choose(item) {
document.getElementById("myImg").innerHTML='<img src="'+item.value+'" style="width:290px" >'
};
</script>
</body>
</html>

Related

HTML (Metro 4) and Google Sheets, Loading Data Asynchronously

I have been trying since October to load an array of items into a select. I'm able to do it with synchronous coding in the template, but not with asynchronous coding (Explanation). I have watched videos, read stackoverflow question after question, read google documentation, metro documentation, and just can't figure it out. This is a google apps script project with a .gs file back end and an .html file that's supposed to be used to load a sidebar.
I have this HTML
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- Metro 4 -->
<link rel="stylesheet" href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css">
</head>
<body>
<!-- Title -->
<h2 style="text-align: center;">Add New Job</h2>
<!-- Job Name -->
<p style="text-align: center;"><span class='mif-chat-bubble-outline'></span> Job Name</p>
<input type="text" data-role="input" data-prepend="Name: ">
<!-- Creator Name -->
<p style="text-align: center;"><span class='mif-user-check'></span> Job Creator</p>
<select data-role="select" id="mySelectList">
<optgroup label="Employees">
<option value="" selected> Loading... </option>
</optgroup>
</select>
<nl></nl>
<p style="text-align: center;">
<button class="button success cycle " id="confirmButton"><span class="mif-checkmark"></span></button>
</p>
<!-- Metro 4 -->
<script src="https://cdn.metroui.org.ua/v4/js/metro.min.js"></script>
<script>
$(function() {
$('#txt1').val('');
console.log("Running updateSelect");
google.script.run
.withSuccessHandler(updateSelect)
.getEmployeeNames();
});
function updateSelect(vA)//array of value that go into the select
{
var select = document.getElementById("mySelectList");
select.options.length = 0;
for (var i=0; i<vA.length;i++){
console.log("Creating items %s, %s", vA[i], vA[i]);
select.options[i] = new Option(vA[i],vA[i]);
console.log ("select.options[i] = %s, select.options = %s.", select.options[i], select.options);
}
}
console.log("My Code Ran");
</script>
</body>
</html>
Which provides this console feedback when ran.
Console Feedback
I have erased all my cookies and cache, disabled all addons, etc, and that did not fix the problem.
Why won't the options change from "Loading..." to the actual new values I've put in? For reference, I have the following code that does work, but it does so in an inefficient way (inside the template itself, instead of being called).
<!-- Creator Name -->
<? var employees = getEmployeeNames(); ?>
<p style="text-align: center;"><span class='mif-user-check'></span> Job Creator</p>
<select data-role="select" id="jobCreator">
<optgroup label="Employees">
<? for (var i = 0; i < employees.length; i++){ ?>
<option> <?= employees[i] ?></option>
<? } ?>
</optgroup>
</select>
Here is the backend script for getEmployeeNames(). I've tried it returning both a 1 dimensional or 2 dimensional array. While the function gives the expected output, the HTML select still does not update with new options.
function getEmployeeNames(){
var employeeSheet = SpreadsheetApp.getActive().getSheetByName('Dropdown Lists');
var names = employeeSheet.getRange(5, 4, employeeSheet.getLastRow(), 1).getValues();
names = removeBlankEntries(names);
Logger.log ('Employee Names "%s"', names);
return names;
}
function removeBlankEntries(arr){
var output = [];
arr.forEach(function(value){
if (value != "" & value != " "){
output.push(value[0]) // add [0] to make it 1d
};
});
return output;
}
Here's an example Logger.log output.
8:27:00 AM Info Employee Names "[PM, Employee 2, Employee 3, Employee 4]"
Or with it set to give a 2d array.
8:28:00 AM Info Employee Names "[[PM], [Employee 2], [Employee 3], [Employee 4]]"
Additionally, here is how the sidebar is loaded in the code.
function loadNewJobSidebar(){
var htmlTemplate = HtmlService
.createTemplateFromFile("addJob");
var htmlOutput = htmlTemplate.evaluate()
.setTitle('Add New Job');
var ui = SpreadsheetApp.getUi();
ui.showSidebar(htmlOutput);
}
Any guidance would be helpful. I thought the video above was the best, and I copied it three or four times without success. I've been coding for a decade - even though it is only my side gig - and I've never had a problem last so many months.
== Sorry this is becoming a monster thread. Below are exact steps for replication ==
Create a new blank Google Sheet.
Open the script editor and create an HTML file called addJob (it will automatically add the .html to the end)
In the HTML file, copy the code exactly from the first snippet in this post titled "I have this HTML"
In the code.gs file, copy the following code
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Manage Sheet')
.addSubMenu (ui.createMenu('Jobs')
.addItem('Add New Job', 'loadNewJobSidebar'))
.addToUi();
}
function getEmployeeNames(){
return ["Bob", "Jamie", "Ted"];
}
function loadNewJobSidebar(){
var htmlTemplate = HtmlService
.createTemplateFromFile("addJob");
var htmlOutput = htmlTemplate.evaluate()
.setTitle('Add New Job');
var ui = SpreadsheetApp.getUi();
ui.showSidebar(htmlOutput);
}
Run the onOpen() function from the script editor. Allow it permission to run.
Go back to the spreadsheet, and on custom menu, select "Manage Sheet -> Jobs -> Add New Job"
The sidebar will load and say "Loading" but will not use the names from the getEmployee() function.
Press F12 and note the console log statements showing the select options should be loaded.
From your updated question, I could understand your current issue. In the case of your script, how about modifying the function updateSelect as follows?
Modified script:
function updateSelect(vA) {
var select = Metro.getPlugin("#mySelectList", 'select');
select.data(Object.fromEntries(vA.map(e => [e, e])));
}
In this modification, it supposes that the value of vA is the one-dimensional array. Please be careful about this.
Reference:
Select of METRO_4

HTML datalist array

Please help me change path of the code so that the drop-down list changes when adding new elements to the array. I’ve been fighting this problem for half a day.Now I have to add manually each time. I tried to find the answer at SO, but all my attempts to change part of the code turned out to be a failure. It seems to me that I still do not understand the logic of HTML Thank you in advance!
js code part:
t.DropdownList = (values); // loading every time before html starts
HTML code part:
<div class="demo" >
<style type="text/css"> .demo { margin: 30px ; color : grey ; font-family :
arial sans-serif ;font-size : 10pt }
o { color : red ; font-size : 14pt }
r { color : gray ; font-size : 14pt }
</style>
<h1>Передача клиента:</h1> <br>
<h1><?= ClientName ?></h1> <br>
<r>Адрес:</r>
<r><?= ClientAdress ?></r> <br>
<r>Менеджер клиента:</r>
<o><?= Manager ?></o> <br>
<br>
<form id='myForm'>
<label for="managers-choice">Выберите менеджера для передачи клиента:</label>
<input list="managers" id="dropdownlist" name="dropdownlist" />
<input
onclick="google.script.run.Message02(document.getElementById('myForm'));myFuncti on();this.disabled=true" type="button" value="Передать" />
</form>
<datalist id="managers">
<option value =<?=DropdownList[0]?> > // in this place I need help, because if the next load the array is shorter, then I will get an undefined result.
<option value =<?=DropdownList[1]?> >
<option value =<?=DropdownList[2]?> >
<option value =<?=DropdownList[3]?> >
<option value =<?=DropdownList[4]?> >
<option value =<?=DropdownList[5]?> >
</datalist>
<script>
$('#dropdownlist').datepicker({ dateFormat: 'dd.mm.yy' });
function myFunction() {
var b = document.getElementById('result');
b.innerHTML = 'Менеджер выбран.';
document.getElementById('dropdownlist').disabled = 'disabled';
//alert('The output has been modified');
return;
}
</script>
<body>
<div id="result">Вы еще не выбрали менеджера.</div>
</body>
</div>
Here's how I do it:
JavaScript:
$(function(){
google.script.run
.withSuccessHandler(function(rObj){
grObj=rObj;
updateSelect(grObj.mnA);
})
.getRecipeList1();//google apps script function on server
});
function updateSelect(vA,id){
var id=id || 'sel1';
var select = document.getElementById(id);
select.options.length = 0;
for(var i=0;i<vA.length;i++)
{
select.options[i] = new Option(vA[i],i);
}
}
So it always gets the latest list every time the page is loaded.

HTML Form: Other input required ONLY if other is selected

I'm currently working on a form with a bunch of options. On some of the questions, there is an "Other" option for the user to type in whatever they choose. I am trying to make it appear only "Other" is selected (I've gotten this to work on the first question but not the others). I am also trying to make this input required ONLY if they select it, so that they can't submit the form having selected "Other" and left it blank.
Here is my HTML and the Javascript for making the other text inputs appear when selected:
<label for="Accom">Question</label>
<table>
<tr>
<td><select name="Accom">
<option value="">Select...</option>
<option value="Handicapped">Handicap Accessibility</option>
<option value="Hearing Impaired">Hearing Impaired</option>
<option value="Visually Impaired">Visually Impaired</option>
<option value="OtherAccom">Other</option>
</select>
</td>
</tr>
<tr>
<td colspan="4">
<label style="" id="other">If Other, Please Specify
<input type="text" name="Other_Accom" size="20"></label></td><tr></table>
.
window.onload=function() {
var other = document.getElementById('other', 'otherAccom','otherDiet');;
other.style.display = 'none';
document.getElementsByName('Title', 'Diet', 'Accom')[0].onchange = function() {other.style.display =(this.value=='Other')? '' : 'none'};
I'm also trying to get a this to work for a checkbox form.
<label for="Interests">Question</label><br>
<input class="checkbox2" TYPE="checkbox" NAME="formInterests[]" required value="Use Cases ||" />Use Cases<br>
<input class="checkbox2" TYPE="checkbox" NAME="formInterests[]" required value="Other" />Other<br>
<label style="" id="other">If Other, Please Specify
<input type="text" name="Other_Interests" size="20"></label>
Thank you very much!
EDIT 1: When I try and duplicate the function, it stops working for everything.
window.onload=function() {
var other = document.getElementById('other', 'otherAccom', 'otherDiet');;
other.style.display = 'none';
document.getElementsByName('Title')[0].onchange = function() {other.style.display = (this.value=='Other')? '' : 'none'};
};
window.onload=function() {
var otherDiet = document.getElementById('other', 'otherAccom', 'otherDiet');;
otherDiet.style.display = 'none';
document.getElementsByName('Diet')[0].onchange = function() {otherDiet.style.display = (this.value=='OtherDiet')? '' : 'none'};
};
document.getElementsByName('Title', 'Diet', 'Accom')[0].onchange = function() {other.style.display =(this.value=='Other')? '' : 'none'};
This selects an array of elements, which you then access by [0], meaning you target the first element (which will be the first of the three that appears in the DOM), and add the onChange listener to it.
This results, as you said yourself:
(I've gotten this to work on the first question but not the others)
Because you actually only run the code on one of the three elements.
You should instead use something like:
document.getElementsByName('Title', 'Diet', 'Accom').forEach(function(element) {
element.onChange = function() {
var target = document.getElementById('Other'+this.name);
if(this.options[this.selectedIndex].value=='Other') {
target.style.display = 'block';
} else {
target.style.display = 'none';
}
};
});
The basic idea is using a forEach to loop through ALL your desired elements, rather than just one of them.
Keep in mind that:
<option value="OtherAccom">Other</option>
does not have value="Other", but value="OtherAccom". Make sure your javascript and html are consistent with eachother.
you can use IDs only once on a page ("other")
you need to rename those other "others" and create seperate functions for them

How to make HTML combo box save values added by user in textbox?

I have made a combobox for a web page. It takes values from user into text box & adds those to list on double click in text box. I want to make user entered values permanently stored as option in list. How can I do it. One more question is how can I count the number of options in list so that I add an element next to that.
Here is my code.
<html>
<head>
<script language="javascript">
function AddListItem(form)
{
var TestVar = form.txtInput.value;
form.txtInput.value = "";
form.select.options[3]=new Option(TestVar, TestVar, true);
}
</script>
<head>
<body>
<form id='Form1'>
<input id='txtInput' type='text' maxlength = "5" size="5" ondblclick="AddListItem(this.form)"/>
<p>
<select id='select'>
<option>abc</option>
<option>cde</option>
<option>efg</option>
</select>
</form>
</body>
</html>
To permanently add you need a server-side script.
To temporarily add you can use javascript:
function addVal(newVal) {
var sel = document.getElementById('select');
var opt = document.createElement("OPTION");
sel.addChildNode(opt);
opt.innerHTML = newVal;
opt.value = newVal; //(alternatively)
}
To count the number of options:
function countOpts() {
var sel document.getElementById('select');
return sel.options.length;
}
(only for conceptual use, not tested as functional)
You add an <option> dynamically like this:
function add(selectId, optText, optValue)
{
var newOption = document.createElement("option")
newOption.text = optText;
newOption.value = optValue;
document.getElementById(selectId).options.add(newOption);
}
selectId is the id of <select>, optText is the text to be displayed in the dropdown and optValue is the value that will be sumbitted to the server.
For your code, call it as
<input id='txtInput' type='text' maxlength = "5" size="5" ondblclick="add('select', this.value, this.value)"/>
As you see, you don't really need to find the length of the options, but you can do it via options.length:
document.getElementById(selectId).options.length;
That said,
You might want to add this to the
dropdown, as well as to pass to the
server, to add to some table, for
instance. You might have to do that
call via AJAX, when you add it to
the dropdown
Adding the new item
on double click of the textbox is
not very usable. On blur might be an
option. Better is an 'Add' button after the
textbox .
Sounds like you need a server-side script then. When you submit the form, you can have a field that is 'remembering' all of the dropdown options:
The simplified HTML:
<form method='post' action=''>
<input name='newDDoption' />
<input type='hidden' name='ddStorage' value='<?PHP echo implode("|||",$ddOptions); ?>' />
<button>GO</button>
</form>
The simplified PHP:
<?PHP
$ddOptions = explode("|||",$_POST['ddStorage']);
$ddOptions[] = $_POST['newDDoption'];
echo "<select>";
for($x=0;$x<count($ddOptions);$x++) {
echo "<option>".$ddOptions[$x]."</option>";
}
echo "</select>";
?>
To explain: PHP saves the ddOptions in the form -> User enters new option -> The form is submitted -> PHP finds the stored values -> PHP pushes on the new value -> PHP loops through and creates your permanent dropdown menu.

implementing select and deselect (toggle) on a SELECT TAG

The current HTML SELECT tag works great for me except for one thing. Is it possible to implement toggling on the current item.
If I have a current selection, I'd like to click it again and "de-select" it. It doesn't work that way now, it simply keeps the current selection "selected".
It seems that I need to know the "previous" selection along with the "current" selection and compare the 2 to see if I need to "de-select" everything. How do I get the previous selection, all I know about is "selectedIndex" which is the current selection.
Is there a way?
To accomplish this you might use a little bit of javascript as follows. I have tested and it seems to work as you requested. I am being verbose for readability, but you can clean once you have it working for you.
<script language="JavaScript" type="text/javascript">
function toggleSelectedValue() {
var selObj = document.getElementById('myList');
var selIndex = selObj.selectedIndex;
var selValue = selObj.options[selIndex].value;
var prevSelValue = document.getElementById('trackSelectedValueHiddenField').value;
if (selValue == prevSelValue) {
//Delect "all" items
selObj.selectedIndex = -1;
document.getElementById('trackSelectedValueHiddenField').value = 0;
}
else {setSelectedValue();}
}
function setSelectedValue()
{
var selObj = document.getElementById('myList');
var selIndex = selObj.selectedIndex;
document.getElementById('trackSelectedValueHiddenField').value = selObj.options[selIndex].value;
}
</script>
</head>
<body>
<div id="wrapper">
<div id="contentDiv" style="height:686px; border: solid 1px red;">
<select multiple="multiple" id="myList" onclick="toggleSelectedValue()">
<option value="1">Test</option>
<option value="2">Test</option>
<option value="3">Test</option>
</select>
<input type="hidden" id="trackSelectedValueHiddenField" value="0" />
</div>
</div>
</body>
</html>