document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, {});
});
const container = document.getElementById("stringcontainer");
var select = createSelect(1);
select.addEventListener('change', hello);
container.appendChild(select);
function add(){
var select1 = createSelect(2);
select1.addEventListener('change', hello);
container.appendChild(select1);
}
function createSelect(num){
//Create array of options to be added
var array = ["Option 1","Option 2","Option 3"];
//Create and append select list
var selectList = document.createElement("select");
selectList.id = "asp"+num;
//selectList.className = "browser-default";
selectList.required = true;
selectList.innerHTML += "<option disabled selected>Choose Option</option>"
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i].split(" ").join("").toLowerCase();
option.text = array[i];
selectList.appendChild(option);
}
return selectList;
}
function hello(){
console.log("Added EventListener");
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.1.0/dist/css/materialize.min.css">
<div class="row">
<div id="stringcontainer"/>
</div><!-- CLOSE ROW -->
<div class="row">
<div class="input-field col s3">
<button id="astring" class="waves-effect waves-light btn-small"
onclick="add()">Add</button>
</div>
</div><!-- CLOSE ROW -->
<script src="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.1.0/dist/js/materialize.min.js"></script>
Called from JS as a function:
Called from a button with the same function:
The result is an invisible unstyled select when you press the button.
I'm using Materialize CSS. The eventListener is also not working properly when adding from the button also. It works for a console log but anything more complex like getSelectedValues(), it fails
I expected the Select to render the same way as the first image. Can anyone explain why this happening and offer a solution?
The problem is, you apply the css only once in the beginning by using
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, {});
});
You have to do the same, each time you add a new select. So, the following should work the way you want it to.
document.addEventListener('DOMContentLoaded', function() {
applyCSS();
});
const container = document.getElementById("stringcontainer");
var select = createSelect(1);
select.addEventListener('change', hello);
container.appendChild(select);
function add(){
var select1 = createSelect(2);
select1.addEventListener('change', hello);
container.appendChild(select1);
applyCSS();
}
function createSelect(num){
//Create array of options to be added
var array = ["Option 1","Option 2","Option 3"];
//Create and append select list
var selectList = document.createElement("select");
selectList.id = "asp"+num;
//selectList.className = "browser-default";
selectList.required = true;
selectList.innerHTML += "<option disabled selected>Choose Option</option>"
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i].split(" ").join("").toLowerCase();
option.text = array[i];
selectList.appendChild(option);
}
return selectList;
}
function hello(){
console.log("Added EventListener");
}
function applyCSS(){
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, {});
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.1.0/dist/css/materialize.min.css">
<div class="row">
<div id="stringcontainer"/>
</div><!-- CLOSE ROW -->
<div class="row">
<div class="input-field col s3">
<button id="astring" class="waves-effect waves-light btn-small"
onclick="add()">Add</button>
</div>
</div><!-- CLOSE ROW -->
<script src="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.1.0/dist/js/materialize.min.js"></script>
I moved the code, which applies the CSS into applyCSS and then call it once in the DOMContentLoaded event listener and also each time the add function is called.
I'm trying to load images from the drop-down button generated based on the Google Sheet's Folder ID
Google Sheet
Out Put
What I'm Trying To ACHIEVE is: I want to load the images on the front end display which is in a google drive folder based on the drop-down list on the front end of Web app.
THE PROBLEM
I'm unable to add the Folder ID into the getPictures() function and also I'm having issues connecting the Folder ID based on the dropdown.
Code.gs
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile('index');
var pictures = getPictures();
htmlOutput.pictures = pictures;
return htmlOutput.evaluate();
}
function getPictures()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var idURL = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues();
var destination_id = '1GNBiddMQZTl3Ti_mKs9CUM541p-yaCnv'; // ID OF GOOGLE DRIVE DIRECTORY;
var destination = DriveApp.getFolderById(destination_id);
var files = destination.getFiles();
var file_array = [];
while (files.hasNext())
{
var file = files.next();
file_array.push(file.getId());
}
return file_array;
}
function getValuesFromSpreadsheet() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
return sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues(); // Retrieve values and send to Javascript
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div class="dropdown">
<button onclick="loadpics()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content"></div>
</div>
<h1>Display Pictures</h1>
<table>
<?for(var i = 0; i < pictures.length; i++) { ?>
<tr><td><img src="https://drive.google.com/uc?export=view&id=<?= pictures[i] ?>" style="width:400px;height:auto;" ></td></tr>
<? } ?>
</table>
</body>
</html>
<script>
function loadpics() {
google.script.run.withSuccessHandler(function(ar) {
let select = document.createElement("select");
select.id = "select1";
select.setAttribute("onchange", "selected()");
document.getElementById("myDropdown").appendChild(select);
ar.forEach(function(e, i) {
let option = document.createElement("option");
option.value = i;
option.text = e;
document.getElementById("select1").appendChild(option);
});
}).getValuesFromSpreadsheet();
};
function selected() {
const value = document.getElementById("select1").value;
console.log(value);
}
</script>
COPY OF GOOGLE SHEET - Click here
I'm not a coder, Could you please help me to achieve my task. Thank in advance.
You can refer to this sample code:
Code.gs
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile('index');
var vehicle = getValuesFromSpreadsheet();
var pictures = getPictures("1"); //show 1st vehicle as default
htmlOutput.vehicle = vehicle;
htmlOutput.pictures = pictures;
return htmlOutput.evaluate();
}
//Get pictures based on the selected option
function getPictures(option)
{
var row = parseInt(option) + 1;
Logger.log("option: "+option+" row: "+row);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var destination_id = sheet.getRange(row, 2).getDisplayValue();
var file_array = [];
Logger.log(destination_id);
try{
var destination = DriveApp.getFolderById(destination_id);
var files = destination.getFiles();
while (files.hasNext())
{
var file = files.next();
file_array.push(file.getId());
}
}catch(err){
Logger.log(err.message);
}
Logger.log(file_array.length);
return file_array;
}
function getValuesFromSpreadsheet() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
return sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues().flat(); // Retrieve values and send to Javascript
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div class="dropdown" >
<div id="myDropdown" class="dropdown-content" style="width:200px;">
<b>Vehicle Menu: </b>
<select id="select1" onchange="selected()">
<?for(var i = 1; i < vehicle.length; i++) { ?>
<option value=<?= i ?>><?= vehicle[i] ?></option>
<? } ?>
</select>
</div>
</div>
<h1>Display Pictures</h1>
<div id="defaultPictures">
<table>
<?for(var i = 0; i < pictures.length; i++) { ?>
<tr><td><img src="https://drive.google.com/uc?export=view&id=<?= pictures[i] ?>" style="width:400px;height:auto;" ></td></tr>
<? } ?>
</table>
</div>
<div id="displayPictures"></div>
</body>
</html>
<script>
function selected() {
//Hide default pictures
var defaultDiv = document.getElementById("defaultPictures");
defaultDiv.style.display = "none";
const value = document.getElementById("select1").value;
console.log(value);
//Update table from the selected option
google.script.run.withSuccessHandler(function(ids) {
//Create a html table string based on the picture ids
let tblHtml = '<table>';
//Create table rows from the picture ids
ids.forEach(id => {
tblHtml += '<tr><td><img src="https://drive.google.com/uc?export=view&id='+id+'" style="width:400px;height:auto;" ></td></tr>';
});
tblHtml += '</table>';
//update div to include the table
console.log(tblHtml);
document.getElementById("displayPictures").innerHTML = tblHtml;
}).getPictures(value);
}
</script>
What it does?
I removed the dropdown button. Instead, I updated the dropdown options using vehicle variable which was initialized in doGet()
I created 2 div which displays your images. <div id="defaultPictures"> displays the table of images initialized using pictures variable set in doGet() while <div id="displayPictures"></div> will display the pictures of the selected option in the dropdown menu.
I modified getPictures() to add option argument which is the option value selected in your dropdown menu. Note that the option value is in zero index. ("Prado" value is 1 while "Prado 2" value is 2)
When initializing pictures variable in your html, I used "Prado" with option value 1 as a default pictures to display.
When a dropdown menu is selected, it will call selected() in your hmtl. Hide the defaultPictures div and create a new table based on the selected option.
Sample Output:
I am trying to have a dependent Dropdown list, Districts based on the value of selected State. But my code is rendering only the first element of the dynamic dropdown list.
<div class="input-field col s3">
<select id="nativeDistr">
<option value="" disabled selected>
Native District
</option>
</select>
<label>Destination District</label>
;
Appscript Code Snippet.
function getDistricts(state) {
Logger.log("Selected State=" + state);
var fileName = "states-and-districts.json";
var files = DriveApp.getFilesByName(fileName);
try {
if (files.hasNext()) {
var file = files.next();
var content = file.getBlob().getDataAsString();
var json = JSON.parse(content).states_districts;
for (var i = 0; i < json.length; i++) {
if (json[i]["state"] === state) {
var districts = json[i]["districts"];
}
}
}
var optList = generateOptions(districts);
Logger.log(optList);
return optList;
} catch (err) {
return "Error getting data";
}
}
Javascript code
<script>
document.getElementById("nativeState").addEventListener("change", getDistr);
function getDistr() {
var state = document.getElementById("nativeState").value;
console.log("state scriptt:" + state);
google.script.run.withSuccessHandler(updatedistricts).getDistricts(state);
}
function updatedistricts(districts) {
console.log("From districts:" + districts);
var nativeDistr = document.getElementById("nativeDistr");
nativeDistr.innerHTML = districts;
M.updateTextFields();
} // When user selects the state the valuee off the state should get registered for district search
Blockquote
Durin execution I am getting the complete list of dynamic dropdown but while rendering the page only the first element is getting displayed.
Blockquote
M.updateTextFields() do not update dynamic dropdown, it updates the text fields. So there is a need to store a global reference to materialize select box to initialize it, post that there is a need to destroy that instance, and then reinitialize the select box again.
<script>
document.addEventListener("DOMContentLoaded", function () {
var elems = document.querySelectorAll("select");
var instances = M.FormSelect.init(elems);
});
document.getElementById("nativeState").addEventListener("change", getDistr);
function getDistr() {
var state = document.getElementById("nativeState").value;
google.script.run.withSuccessHandler(updatedistricts).getDistricts(state);
}
function updatedistricts(distrList){
nativeDistr.innerHTML = distrList;
var subcatSelectElem = document.querySelectorAll("select");
var subcatSelectInstance = M.FormSelect.init(subcatSelectElem, {});
}
Credit for soln.: Chicago Computer Classes
Need to send dynamic (not hardcode) data to a select element.
This code works great in one of my sheets but doesn't work in the other sheet.
The "select" element doesn't get updated with the options I send..
I don't get an error message either.
I've spent a lot of time twitching it and trying to find why but still don't see what's wrong.
p.s. I used a dummy object to send the data for testing purpose.
The html (used MaterializeCss framework)
<select class="icons browser-default" id="selName" onChange ="getNameText();">
<option value="" disabled selected>Choose week</option>
<div id = "err"></div>
//select element initialization in framework
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var options = handlers()
var instances = M.FormSelect.init(elems);
});
function handlers() {
var success = google.script.run.withSuccessHandler(addOptions).getNamesForDropdown()
var failure = google.script.run.withFailureHandler(showError).getNamesForDropdown()
return;
}
function addOptions(names) {
var selectTag = document.getElementById("selName") //select tag
for (var k in names) {
var thisID = k;
var thisText = names[k];
var option = document.createElement("option"); //creating option
option.text = thisText
option.value = thisID;
selectTag.add(option);
}
}
function showError() {
var err = document.getElementById("err").innerHTML = "There was an error."
}
//get the text of selected option
function getNameText() {
var sel = document.getElementById("selName")
var nameText = sel.options[sel.selectedIndex].text;
return nameText;
}
Dummy object I send:
function getNamesForDropdown() {
var namesObj = {
one: "blah",
two: "blahblah"
}
return namesObj;
}
Here's the result what I get (on the screen you there's only hardcoded option):
I handled it. I added a class "browser-default" to the select and the options got updated. This class comes from MaterializeCss Framework.
I am trying to load the first available option to the third drop-down.
The code is as below.
var categories = [];
categories["startList"] = ["C.","C#.","D.","Eb.","E.","F.","F#.","G.","Ab.","A.","Bb.","B."]; // Level 1
categories["C."] = ["C","C7","Cm","Cm7","Cmaj7","Csus4","Caug","Cdim"];
categories["C"] = ["032010","335553","133211","543210",""];
var nLists = 3; // number of lists in the set
function fillSelect(currCat,currList){
var step = Number(currList.name.replace(/\D/g,""));
for (i=step; i<nLists+1; i++) {
document.forms[0]['List'+i].length = 1;
document.forms[0]['List'+i].selectedIndex = 0;
}
var nCat = categories[currCat];
for (each in nCat) {
var nOption = document.createElement('option');
var nData = document.createTextNode(nCat[each]);
nOption.setAttribute('value',nCat[each]);
nOption.appendChild(nData);
currList.appendChild(nOption);
}
}
function init() { fillSelect('startList',document.forms[0]['List1']);
fillSelect('startList',document.forms[0]['List4']);
fillSelect('startList',document.forms[0]['List7']);
}
navigator.appName == "Microsoft Internet Explorer"
? attachEvent('onload', init, false)
: addEventListener('load', init, false);
function getValues() {
var str = '';
for(i = 1; i < 6; i++) {
document.createElement('select')
str += document.getElementById('List' + i).value+'\n';
document.getElementById('creation').innerHTML=""; }
}
<select name='List4' id="List4" onchange="fillSelect(this.value,this.form['ch2'])"><option selected></option></select>
<select name='ch2' id="ch2" onchange="fillSelect(this.value,this.form['tb2'])"><option selected></option></select>
<select name='tb2' id="tb2"><option selected></option></select>
<input id="f2" type="text" size="1" value=1 class=copystuff>
<button onclick="do2()">Do2</button><br>
Now the problem is that when I try to select the second drop down menu "ch2", I want the first value to be loaded automatically in the third dropdown "tb2" according to the selection that I make in the second menu. For eg, if I select C. in the first menu, C in the second menu, I want 032010 to be already selected in the next menu. Is there any simple way to do this?
I have changed your code up a good bit. But I think it's a bit more readable, and may be easier to extend to more forms, categories, and selects.
First here is the working JSFiddle: http://jsfiddle.net/z1sw2bfq/
Second, here is the Fiddle code. Please see the comments for additional context.
<script>
//create a blank object to hold the select lists
var lists = { };
//create an object to hold the categories text arrays
var categories = {
"startList": ["C.","C#.","D.","Eb.","E.","F.","F#.","G.","Ab.","A.","Bb.","B."], // Level 1
"C.": ["C","C7","Cm","Cm7","Cmaj7","Csus4","Caug","Cdim"],
"C": ["032010","335553","133211","543210",""]
};
function init() {
//load the SELECT element from the form into lists
//Get all of the selects in forms[0]...
var selects = document.forms[0].getElementsByTagName("select");
for (var i in selects) {
//...and load those into lists.
lists[selects[i].id] = selects[i];
//Ex: creates a property like "lists.List4" also referenced by "list['List4']")
// which equals the select element with id List4
}
//enter the list name and the select id
fillSelect('startList', 'List4');
}
function fillSelect(currCatName, currListName){
//get the category
var cat = categories[currCatName];
//verify the category is valid
if (cat) {
//get the select
var select = lists[currListName];
//verify the select is valid
if (select) {
//clear the select
for (var i = select.options.length-1; i>=0; i--)
select.remove(i);
//check the data-first attribute
var datafirst = select.getAttribute("data-first");
if (datafirst == "blank") {
var opt = document.createElement('option');
opt.value = "";
opt.text = "";
select.add(opt);
}
//load the select
for (var j in cat) {
var opt = document.createElement('option');
opt.value = cat[j];
opt.text = cat[j];
select.add(opt);
}
}
}
}
//best to use feature detection instead of browser detection
if (window.attachEvent)
window.attachEvent('onload', init, false);
else
window.addEventListener('load', init, false);
</script>
<form action="#" method="get">
<!--
I added a "data-first" attribute to the selects. This will be used to determine if the
first option in the select is a blank or the first item in the list.
-->
<select name='List4' id="List4" onchange="fillSelect(this.value,'ch2')" data-first="blank"></select>
<select name='ch2' id="ch2" onchange="fillSelect(this.value,'tb2')" data-first="blank"></select>
<select name='tb2' id="tb2" data-first="first"></select>
</form>