google apps script web app dynamic list from form - javascript

I have a Google Apps Script web app that contains an HTML form with a couple of drop-down lists. When the user submits their choices, a function looks them up in a Google spreadsheet and returns corresponding values in an array. This array could have any length, and I am having trouble getting it to display as an HTML list without having a set list length.
I have this GAS script:
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function discern(formObject) {
var stage = formObject.stage;
var service = formObject.service;
var ss = SpreadsheetApp.openById(ID);
var dataSheet = ss.getSheetByName('Sheet1');
var dataRange = dataSheet.getDataRange();
var data = dataRange.getValues();
var array = [];
for(var i = 0; i < data.length; i++) {
if(data[i][1].indexOf(stage) > -1) {
if(data[i][2].indexOf(service) > -1) {
array.push(data[i][0]);
}
}
}
return array;
}
And this HTML:
<script>
function printList(array) {
var div = document.getElementById('results');
var list = HtmlService.createHtmlOutput('<ul>');
for (var i = 0; i < array.length; i++) {
list.append('<li>' + array[i] + '</li>');
}
list.append('</ul>');
}
</script>
<form id="myForm">
<h3>Farming Stage</h3><br>
Select your farming stage.<br>
<select name="stage">
<option etc etc etc
</select><br>
<h3>Services</h3><br>
Select the service for which you are looking<br>
<select name="service">
<option value= etc etc etc</option>
</select><br>
<br><input type="button" value="Discern"
onclick="google.script.run
.withSuccessHandler(printList)
.discern(this.parentNode)"/>
</form>
<ul id="results"></ul>
(I've replaced some sections with "etc" to save space. The form itself is not the issue.)
Anyway, right now the app returns nothing. Earlier I had the printList function as:
function printList(array) {
var div = document.getElementById('output');
div.innerHTML =
'<ul><li>' + array[0] +
'</li><li>' + array[1] +
'</li><li>' + array[2] +
'</li><li>' + array[3] +
'</li><li>' + array[4] +
'</li></ul>';
}
This version worked, but it was limited to 5 list slots, and the unused slots showed up as "undefined," which was annoying.
Does anyone have any suggestions? Was I close with the 'for' loop in my printList function? Is there another simple way to go about this? I would really appreciate any help or feedback.
Thanks,
Bill

You get the div results do you mean to append the list to the html?
<script>
function printList(array) {
var div = document.getElementById('results');
var list = HtmlService.createHtmlOutput('<ul>');
for (var i = 0; i < array.length; i++) {
list.append('<li>' + array[i] + '</li>');
}
list.append('</ul>');
// ?
div.innerHTML = list.getContent();
}
</script>
edit Also I think you need to getContents of the html Object.
You could not use the HTMLService. Personally I never got it to work the way I wanted it to when I used it. (a couple years ago).
Why not use your loop and just append the string to the div like this.
<script>
function printList(array) {
var div = document.getElementById('results');
var list = '<ul>');
for (var i = 0; i < array.length; i++) {
list += '<li>' + array[i] + '</li>';
}
list += '</ul>';
div.innerHTML = list;
}
</script>

For whatever reason, it worked when I did it this way:
...<br><input type="button" value="Discern"
onclick="google.script.run
.withSuccessHandler(showThings)
.discern(this.parentNode)"/>
</form>
<p>List of services:</p>
<ul id="things">
<li>Waiting...</li>
</ul>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
function showThings(array) {
var list = $('#things');
list.empty();
for (var i = 0; i < array.length; i++) {
list.append('<li>' + array[i] + '</li>');
}
}
</script>

Related

Returning html code in javascript

I want to print html code in Javascript code.
I want to open and close the bottom line of five li tags. How can I do this with a for loop
jQuery(document).ready(function () {
InsertLi();
});
function InsertLi(){
var count = 5;
for (var i = 0; i < count; i++) {
var codeBlock = ' <li>' + i + '</li>';
$(".bildirimMetin").html(codeBlock);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="bildirimMetin">
</ul>
You need to use append function instead. html function every time overrides your html content with the new content and you get only the last one. Also create your string with 5 li-s and then call the append at the end to work with DOM one time and have more performance.
function InsertLi() {
var count = 5;
var codeBlock = '';
for (var i = 0; i < count; i++) {
codeBlock += ' <li>' + i + '</li>';
}
$(".bildirimMetin").append(codeBlock);
}
jQuery(document).ready(function () {
InsertLi();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="bildirimMetin"></ul>
If you have only one item with bildirimMetin class, it will be better to use id instead of class.
Well, another solution, close to your code, with html, store all strings in your variable via += then you must define your variable before for loop also move your html after it. Your current code not working because it just store last string not all.
InsertLi();
function InsertLi() {
var count = 5;
var codeBlock = '';
for (var i = 0; i < count; i++) {
codeBlock += '<li>' + i + '</li>';
}
$(".bildirimMetin").html(codeBlock);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="bildirimMetin">
</ul>
you had a couple issues. One was overwriting the inner HTML instead of appending. The other was a syntax issue.
function InsertLi(){
var count = 5;
for (var i = 0; i < count; i++) {
var codeBlock = ' <li>' + i + '</li>';
$(".bildirimMetin").append(codeBlock);
}
}
jQuery(document).ready(function () {
InsertLi();
}
);

Push data to different elements, depending on column in google spreadsheet with GAS?

I am working in Google Spreadsheet with GAS, and I am trying to push some data from a spreadsheet to an HTML page, and right now that is working. But I am managing to do is grabbing all the values, and each time it hits a new row, it grabs all the values in that row pushes them into a newly created <div>. But I would like to do is have some column functionality also so that the different columns gets pushed to a different element like an <input> or a <select> element.
I tried out some things where I declared some variables for the desired columns, and trying to pushing them to the HTML one by one, but it didn't work out.
Here is my data:
This is what it looks like in the HTML:
This is what I am going for:
Would it be better to publish this into tables? Because I simply thought of creating divs with classes and set their width and line breaks?
Below is the code I described in the beginning:
Code.gs
var ss = SpreadsheetApp.openById("1c7IwmyBrbNq5xwzo-7EyFewCx31WpfP4EzLpkHawffI");
function doGet(request) {
return HtmlService.createTemplateFromFile('stuff')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getStitchOrders(){
var ordersName = [];
var sheet = ss.getSheetByName("Cat1");
var subRange = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn());
var orders = subRange.getValues();
for (var i = 0; i < orders.length; i++) {
ordersName.push( orders[i] )
}
return ordersName;
}
stuff.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="orders">
//Data is listed here.
</div>
<script>
$(function() {
google.script.run.withSuccessHandler(buildOrderList).getStitchOrders();
});
function buildOrderList(ordersName) {
var rows = $('#orders');
for (var i = 0; i < ordersName.length; i++) {
rows.append('<div name="' + ordersName[i] + '">' + ordersName[i] + '</div>');
}
}
</script>
Any suggestions?
Edit
Code2.gs
var ss = SpreadsheetApp.openById("1c7IwmyBrbNq5xwzo-7EyFewCx31WpfP4EzLpkHawffI");
function doGet(request) {
return HtmlService.createTemplateFromFile('stuff2')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getStitchOrders(){
var ordersName = [];
var sheet = ss.getSheetByName("Sheet");
var subRange = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn());
var orders = subRange.getValues();
for (var i = 0; i < orders.length; i++) {
ordersName.push( {
name: orders[i][0],
status: orders[i][1],
comment: orders[i][2]
} );
}
return JSON.stringify(ordersName);
}
stuff2.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="orders">
</div>
<script>
$(function() {
google.script.run.withSuccessHandler(buildOrderList).getStitchOrders();
});
function buildOrderList(ordersName) {
var arr = JSON.Parse(ordersName);
var rows = $('#orders');
for (var i = 0; i < arr.length; i++) {
rows.append('<div name="' + arr[i].name + '">' + arr[i].name + '</div>');
}
}
</script>
consider returning the data with this type of pattern:
for (var i = 0; i < orders.length; i++) {
ordersName.push( {
name: orders[i][0],
status: orders[i][1],
comment: orders[i][2]
} );
}
return JSON.stringify(ordersName);
then back in the client-side JS we can turn it back into an Array to loop through:
function buildOrderList(ordersName) {
var arr = JSON.parse(ordersName);
var rows = $('#orders');
for (var i = 0; i < arr.length; i++) {
// values can now be referenced via...
// arr[i].name
// arr[i].status;
// arr[i].comment;
rows.append(...);
}
}
how to then style the divs and the elements inside them to align up like a table is more a CSS question.

For loop through Array only shows last value

I'm trying to loop through an Array which then uses innerHTML to create a new element for every entry in the array. Somehow my code is only showing the last value from the array. I've been stuck on this for a few hours and can't seem to figure out what I'm doing wrong.
window.onload = function() {
// Read value from storage, or empty array
var names = JSON.parse(localStorage.getItem('locname') || "[]");
var i = 0;
n = (names.length);
for (i = 0; i <= (n-1); i++) {
var list = names[i];
var myList = document.getElementById("list");
myList.innerHTML = "<li class='list-group-item' id='listItem'>"+ list + "</li>" + "<br />";
}
}
I have a UL with the id 'list' in my HTML.
Change your for loop:
for (i = 0; i <= (n-1); i++) {
var list = names[i];
var myList = document.getElementById("list");
myList.innerHTML += "<li class='list-group-item' id='listItem'>"+ list + "</li>" + "<br />";
}
Use += instead of =. Other than that, your code looks fine.
I suggest you to first make a div by create element. there you add your innerHTML and after that you can do the appendchild. That will work perfectly for this type of scenario.
function displayCountries(countries) {
const countriesDiv = document.getElementById('countriesDiv');
countries.forEach(country => {
console.log(country.borders);
const div = document.createElement('div');
div.classList.add('countryStyle');
div.innerHTML = `
<h1> Name : ${country.name.official} </h1>
<h2> Capital : ${country.capital} </h2>
<h3> Borders : ${country.borders} </h3>
<img src="${country.flags.png}">
`;
countriesDiv.appendChild(div);
});
}

Changing radio buttons name using Javascript

I'm using a simple JS duplicate function to duplicate a div. Inside is form information with radio buttons, including one group called 'getOrRequest'. Each div represents a book and needs to have its own 'getOrRequest' value.
The name needs to be changed in order to make each duplicated group of radio buttons selectable without affecting every other radio button. What is the best way to change these values?
Here is how I'm duplicating the div, in case that is the issue.
var bookInfo = document.getElementById('bookInformation');
var copyDiv = document.getElementById('addListing').cloneNode(true);
bookInfo.appendChild(copyDiv);
I then have tried a couple methods of changing the name value. Like this:
bookInfo.copyDiv.getOrRequest_0.setAttribute("name", "'getOrRequest' + idNumber + '[]'");
bookInfo.copyDiv.getOrRequest_1.setAttribute("name", "'getOrRequest' + idNumber + '[]'");
As well as this:
bookInfo.copyDiv.getOrRequest_0.name = 'getOrRequest' + idNumber + '[]';
bookInfo.copyDiv.getOrRequest_1.name = 'getOrRequest' + idNumber + '[]';
getOrRequest_0 and getOrRequest_1 are the ID's of the input values, but I've tried it a few ways now and nothing seems to work. Thanks in advance!
EDIT: MORE INFO
Here is the specific code I'm using:
function addAnotherPost(){
var bookInfo = document.getElementById('bookInformation');
var copyDiv = document.getElementById('addListing').cloneNode(true);
var size = copyDiv.childNodes.length;
copyDiv.id = 'addListing' + idNumber;
for(var j = 0; j < size; j++){
if(copyDiv.childNodes[j].name === "getOrRequest[]"){
copyDiv.childNodes[j].name = "getOrRequest" + idNumber + "[]";
}
}
bookInfo.appendChild(copyDiv);
idNumber++;
}
And it just doesn't seem to work.. The divs are duplicating, but the name value is not changing.
You can try this - http://jsfiddle.net/ZKHF3/
<div id="bookInformation">
<div id="addListing">
<input type="radio" name="addListing0[]" />
<input type="radio" name="addListing0[]" />
</div>
</div>
<button id="button">Add Listing</button>
<script>
document.getElementById("button").addEventListener("click", AddListing, false);
var i = 1;
var bookInfo = document.getElementById('bookInformation');
function AddListing() {
var copyDiv = document.getElementById('addListing').cloneNode(true);
var size = copyDiv.childNodes.length;
copyDiv.id = "listing" + i;
for ( var j = 0; j < size; j++ ) {
if ( copyDiv.childNodes[j].nodeName.toLowerCase() == 'input' ) {
copyDiv.childNodes[j].name = "addListing" + i + "[]";
}
}
bookInfo.appendChild(copyDiv);
i++;
}
</script>
The trouble is you are looking for child nodes of the div, but the check boxes are not child nodes, they are descendant nodes. The nodes you are looking for are nested within a label. Update your code to look for all descendant inputs using copyDiv.getElementsByTagName("input"):
var idNumber = 0;
function addAnotherPost() {
var bookInfo = document.getElementById('bookInformation');
var copyDiv = document.getElementById('addListing').cloneNode(true);
copyDiv.id = 'addListing' + idNumber;
var inputs = copyDiv.getElementsByTagName("input");
for(var j = 0; j < inputs.length; j++){
if(inputs[j].name === "getOrRequest[]"){
inputs[j].name = "getOrRequest" + idNumber + "[]";
}
}
bookInfo.appendChild(copyDiv);
idNumber++;
}
http://jsfiddle.net/gilly3/U5nsa/

Append an Array to an Unordered List

What I'm trying to accomplish with this code is to output the array alphabet as a series of list items into an existing unordered list in the actual markup. I've got the array into list items, but I can't figure out how to tell it to append itself to an existing unordered list <ul id="itemList"></ul>.
var itemsExist = true;
var indexNum = 0;
var unorderedList = document.getElementById('itemList');
var alphabet= new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
function write_letters(){
for (i = 0; i < alphabet.length; i++ ) {
document.write('<li>' + alphabet[indexNum++] + '</li>');
}
}
if (itemsExist){
write_letters();
} else {
document.write("error!");
}
Don't use document.write to do it. You should act like this:
function write_letters(){
var letters = "";
for (var i = 0; i < alphabet.length; i++ ) {
//Also I don't understand the purpose of the indexNum variable.
//letters += "<li>" + alphabet[indexNum++] + "</li>";
letters += "<li>" + alphabet[i] + "</li>";
}
document.getElementById("itemList").innerHTML = letters;
}
More proper way is to use DOM (in case you want full control of what's coming on):
function write_letters(){
var items = document.getElementById("itemList");
for (var i = 0; i < alphabet.length; i++ ) {
var item = document.createElement("li");
item.innerHTML = alphabet[i];
items.appendChild(item);
}
}
You can use a combination of createElement() and appendChild() to add new HTML elements within another HTML element. The code below should work for you:
<html>
<head>
<title>Script Test</title>
</head>
<body>
<ul id="itemList"></ul>
</body>
<script>
var itemsExist = true;
var indexNum = 0;
var unorderedList = document.getElementById('itemList');
var alphabet= new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
var myElement;
function write_letters(){
for (i = 0; i < alphabet.length; i++ ) {
// Create the <LI> element
myElement = document.createElement("LI");
// Add the letter between the <LI> tags
myElement.innerHTML = alphabet[indexNum++];
// Append the <LI> to the bottom of the <UL> element
unorderedList.appendChild(myElement);
}
}
if (itemsExist){
write_letters();
} else {
document.write("error!");
}
</script>
</html>
Note how the script exists below the body tag. This is important if you want your script to work the way you wrote it. Otherwise document.getElementById('itemList') will not find the 'itemList' ID.
Try to reduce the actions on the DOM as much as possible. Every appendChild on unorderedList forces the browser to re-render the complete page. Use documentFragement for that sort of action.
var frag = document.createDocumentFragment();
for (var i = alphabet.length; i--; ) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(alphabet[indexNum++]));
frag.appendChild(li);
}
unorderedList.appendChild(frag);
So there will be only one DOM action which forces a complete redraw instead of alphabet.length redraws

Categories

Resources