Problems working with dependent values from HTML to Spreadsheet? - javascript

I am working on a dynamic dependent dropdown, and I have gotten very far and learned alot through stackoverflow, so thanks to everyone. Anyways Iv'e reached a stopping point where something isn't working?
Here is a url for the online script: https://script.google.com/macros/s/AKfycbzWi3JymieWMAGVLQVl2xEXCd_eo85hWercHAFkNrqH5dkvWWQd/exec
and a url to the spreadsheet: https://docs.google.com/spreadsheets/d/1BK5urtTzqZ2kc89ZnbeMSIm2-bt4KLNTQghsxn0cXBI/edit#gid=0
Two lists are generated the first one lists all the sheets in the spreadsheet, and the second one, should, list the values in the first row.
So below you see my index.html:
index.html
<div>
<select id="categories" onchange="google.script.run.withSuccessHandler(buildSubCategoriesList)
.getSubCategories()">
<option>Loading...</option>
</select>
<select id="subCategories">
<option>Loading...</option>
</select>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// This code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(buildCategoriesList)
.getCategories();
});
function buildCategoriesList(sheetsName) {
var list = $('#categories');
list.empty();
for (var i = 0; i < sheetsName.length; i++) {
list.append('<option value="' + sheetsName[i] + '">' + sheetsName[i] + '</option>');
}
}
</script>
<script>
function buildSubCategoriesList(columnsName) {
var list = $('#subCategories');
list.empty();
for (var i = 0; i < columnsName.length; i++) {
list.append('<option value="' + columnsName[i] + '">' + columnsName[i] + '</option>');
}
}
</script>
and here is the code:
code.gs
function doGet(request) {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
var ss = SpreadsheetApp.openById("1BK5urtTzqZ2kc89ZnbeMSIm2-bt4KLNTQghsxn0cXBI");
function getCategories(){
sheetsName = [];
var sheets = ss.getSheets();
for( var i = 0; i < sheets.length; i++ ){
sheetsName .push(sheets[i].getName() )
};
return sheetsName;
}
function getSubCategories(categories){
columnsName = [];
var sheet = ss.getSheetByName(categories);
var lastCol = sheet.getLastColumn();
var subRange = sheet.getRange("A1"+lastCol);
var columns = subRange.getValues;
for( var i = 0; i < sheets.length; i++ ){
columnsName .push(columns[i])
};
return columnsName;
}
I have tried alot of things, any I really can't seem to figure out a way to make this work. So I am asking you guys, any suggestions?

A couple of things have to be corrected in your code for it to work:
index.html file: your call to getSubCategories() function in onchange event on categories select did not pass the selected value
index.html file: populating a <select> element with options does not trigger change event - thus you need to trigger it manually to update Sub-categories select
code.gs file: in getSubCategories() function, your getRange() call retrieved 3 rows in column A instead of 3 cell in row 1
code.gs file: again in getSubCategories() function your getValues call has to be getValues(); and since getValues() returns a 2D array, you have to get column values from the first array item only (first row), hence it should be getValues()[0]
Corrected working code attached below:
code.gs
var ss = SpreadsheetApp.openById("1BK5urtTzqZ2kc89ZnbeMSIm2-bt4KLNTQghsxn0cXBI");
function doGet(request) {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getCategories(){
var sheetsName = [];
var sheets = ss.getSheets();
for( var i = 0; i < sheets.length; i++ ){
sheetsName.push( sheets[i].getName() )
}
return sheetsName;
}
function getSubCategories(categories){
var columnsName = [];
var sheet = ss.getSheetByName(categories);
var subRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
var columns = subRange.getValues()[0];
for( var i = 0; i < columns.length; i++ ){
columnsName.push( columns[i] )
}
return columnsName;
}
index.html
<div>
<select id="categories" onchange="google.script.run.withSuccessHandler(buildSubCategoriesList)
.getSubCategories(this.value)">
<option>Loading...</option>
</select>
<select id="subCategories">
<option>Loading...</option>
</select>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
// This code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(buildCategoriesList).getCategories();
});
function buildCategoriesList(sheetsName) {
var list = $('#categories');
list.empty();
for (var i = 0; i < sheetsName.length; i++) {
list.append('<option value="' + sheetsName[i] + '">' + sheetsName[i] + '</option>');
}
list.trigger("change");
}
function buildSubCategoriesList(columnsName) {
console.log(columnsName);
var list = $('#subCategories');
list.empty();
for (var i = 0; i < columnsName.length; i++) {
list.append('<option value="' + columnsName[i] + '">' + columnsName[i] + '</option>');
}
}
</script>

Related

Display message if array is empty

I'm displaying favorites from localStorage on a page and I'd like to display a message for people that don't have any favorites yet.
This is the div that displays the list which I'd like to repurpose to display the message below when there are no favorites:
<div id='favorites'></div>
And here is the JavaScript that normally shows the favorites:
var options = Array.apply(0, new Array(localStorage.length)).map(function (o, i){
return localStorage.key(i);
});
function makeUL() {
var LIs = '';
var noFavs = 'Hmm, you must\'ve not favorited anything yet. Maybe you\'ll like this one.';
var len = options.length;
if (len === 0) {
document.getElementById('nofavorites').innerHTML = noFavs;
} else {
for (i = 0; i < len; i += 1) {
LIs += '<li>' + options[i] + '</li>';
}
return '<ul>' + LIs + '</ul>';
}
}
document.getElementById('favorites').innerHTML = makeUL();
Right now it just shows undefined.
This is in your html:
<div id='favorites'></div>
<div id='nofavorites'></div>
Your javascript:
var options = Array.apply(0, new Array(localStorage.length)).map(function (o, i){
return localStorage.key(i);
});
function loadFavoriteHTML() {
var favoriteHtml = '';
var noFavs = 'Hmm, you must\'ve not favorited anything yet. Maybe you\'ll like this one.';
var len = options.length;
// Clear html lists
document.getElementById('favorites').innerHTML = '';
document.getElementById('nofavorites').innerHTML = '';
if (len === 0) {
document.getElementById('nofavorites').innerHTML = noFavs;
} else {
for (var i = 0; i < len; i++) {
favoriteHtml+= '<li>' + options[i] + '</li>';
}
var ulHtml= '<ul>' + favoriteHtml+ '</ul>';
document.getElementById('favorites').innerHTML = ulHtml;
}
}
loadFavoriteHTML();
Your code is show undefine because when you dont have favorites list you dont return anything in you makeUI function, and by default the return value is undefined in a function if you dont have return.
I changed your code to set the UI in the function because you edit 2 different div. there is others way to do it. this is a one way.
It's because the makeUL function doesn't return any value when there's no element in the options array.
You'll have to choose between: updating your element inside your function
OR getting the value to insert inside your HTML element returned by your function. But you shouldn't do both.
You might want to change your code into something like this?
var options = Array.apply(0, new Array(localStorage.length)).map(function (o, i) {
return localStorage.key(i);
});
function makeUL() {
var LIs = '';
var noFavs = 'Hmm, you must\'ve not favorited anything yet. Maybe you\'ll like this one.';
var len = options.length;
if (len === 0) {
document.getElementById('favorites').innerHTML = noFavs;
} else {
for (var i = 0; i < len; i += 1) {
LIs += '<li>' + options[i] + '</li>';
}
document.getElementById('favorites').innerHTML = '<ul>' + LIs + '</ul>';
}
}
makeUL();
Plus, you're targeting a nofavorites element that doesn't exist in your example.

Element not being selected dynamically from datalist

I have this list on my HTML page of country codes as part of a form:
<input list="countryCodesLst" name="countryCodes">
<datalist id="countryCodesLst">
...
<option value="93">
<option value="355">
<option value="213">
...
And I have this code in javascript after the list mentioned above:
<script type="text/javascript">
var codes = [{"BD": "880", "BE": "32"...}];
var what = $.get("http://ipinfo.io", function(response) { updateResponse(response);}, "jsonp");
function updateResponse(data){
countryCode = data;
}
var CC = countryCode.country;
console.log(CC);
function getValueByKey(key, data) {
var i, len = data.length;
for (i = 0; i < len; i++) {
if (data[i] && data[i].hasOwnProperty(key)) {
return data[i][key];
}
}
return -1;
}
var found = getValueByKey(CC,codes);
console.log(found);
var element = document.getElementById('countryCodesLst');
element.innerHTML = found;
</script>
However, even though I see that the code does found the value, it does not set the value in the dropdown list.
Can you please help me understand why?

Add certain values from JSON object to javascript array

Update: I've tried the suggestions in the comments and it's still not working. I really have no idea why. I've consolidated it to a single loop and fixed the syntax errors noted. Here's the code as it looks now:
$(function() {
$("#json-one").change(function() {
var $dropdown = $(this);
$.getJSON("washroutines.json", function(data) {
var vals = [];
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
$jsontwo.append("<option value=\"" + data[i].model + "\">" + data[i].model + "</option>");
}
}
});
});
});
Any additional help would be much appreciated!
Original question:
I'm trying to create dependent drop down menus using a json object, and I'm having trouble getting the second menu to populate based on the first. When the first menu changes, the second goes to a bunch of "undefined"s.
$.getJSON("washroutines.json", function(data) {
var vals = [];
for (i = 0; i < data.length; i++){
if (data.make = $dropdown.val()) {
vals.push(data.model);
}
}
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (i = 0; i < vals.length; i++){
$jsontwo.append("<option value\"" + vals[i] + "\">" + vals[i] + "</option>");
}
Please use small words when explaining things to me, I'm new at this!
contents of the JSON:
[{"make":"Maytag","model":"Bravos","prewashCycle":"Whitest Whites"},
{"make":"Maytag","model":"Awesome","prewashCycle":"Awesome Whitest Whites"},
{"make":"Whirlpool","model":"Cabrio","prewashCycle":"Extra Heavy"},
{"make":"Kenmore","model":"Elite","prewashCycle":"Awesome"}]
Try changing your for loop for this
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
vals.push(data[i].model);
}
}

Get column by name from a <select> with GAS in Google Sheets?

I am working on a GAS powered dependent dropdown, which I have now come very close to achieving with the help from stackoverflow, thanks to all.
But I have come to a point where there is a lack of documentation? Or answer to.
I am trying to get a specific column by name, by that I find the column that has the header/top row value of a certain input. In this case it's a dropdown running on an HTML page, that speaks with GAS.
Most of the script works just fine, it's the building what I call topics in the buttom of the HTML and the Code.gs that is causing me some trouble. Right now it's not getting the columns in anyway, but that's because I haven't found a way of doing it yet. The parts that are not working right now are: function buildTopicsList(rowsName) in the HTML and the function getTopics(subCategories,categories) in Code.gs
Here I want to get all the rows in a column with a "header" selected from a dropdown in the html.
The full HTML looks like this:
index.html
<div>
<select id="categories" onchange="google.script.run.withSuccessHandler(buildSubCategoriesList)
.getSubCategories(this.value)">
<option>Loading...</option>
</select>
<select id="subCategories" onchange="google.script.run.withSuccessHandler(buildTopicsList)
.getTopics(this.value)">
<option>Loading...</option>
</select>
<select id="topics">
<option>Loading...</option>
</select>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
// This code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(buildCategoriesList).getCategories();
});
function buildCategoriesList(sheetsName) {
var list = $('#categories');
list.empty();
for (var i = 0; i < sheetsName.length; i++) {
list.append('<option value="' + sheetsName[i] + '">' + sheetsName[i] + '</option>');
}
list.trigger("change");
}
function buildSubCategoriesList(columnsName) {
console.log(columnsName);
var list = $('#subCategories');
list.empty();
for (var i = 0; i < columnsName.length; i++) {
list.append('<option value="' + columnsName[i] + '">' + columnsName[i] + '</option>');
}
list.trigger("change");
}
function buildTopicsList(rowsName) {
console.log(rowsName);
var list = $('#topics');
list.empty();
for (var i = 0; i < rowsName.length; i++) {
list.append('<option value="' + rowsName[i] + '">' + rowsName[i] + '</option>');
}
}
</script>
and the code:
Code.gs
var ss = SpreadsheetApp.openById("1BK5urtTzqZ2kc89ZnbeMSIm2-bt4KLNTQghsxn0cXBI");
function doGet(request) {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function getCategories(){
var sheetsName = [];
var sheets = ss.getSheets();
for( var i = 0; i < sheets.length; i++ ){
sheetsName.push( sheets[i].getName() )
}
return sheetsName;
}
function getSubCategories(categories){
var columnsName = [];
var sheet = ss.getSheetByName(categories);
var subRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
var columns = subRange.getValues()[0];
for( var i = 0; i < columns.length; i++ ){
columnsName.push( columns[i] )
}
return columnsName;
}
// this here is not working:
function getTopics(subCategories,categories){
var rowsName = [];
var sheet = ss.getSheetByName(categories);
var topRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
var rows = topRange.getValues()[0];
for( var i = 0; i < rows.length; i++ ){
rowsName.push( rows[i] )
}
return rowsName;
}
Any suggestions?
The server function getTopics(subCategories,categories) is being called by onchange attribute:
onchange="google.script.run.withSuccessHandler(buildTopicsList)
.getTopics(this.value)"
this.value is being passed to the getTopics(subCategories,categories) function. But the getTopics(subCategories,categories) function accepts two parameters, not one. And the first parameter, subCategories is never being used in the code. That's why you aren't getting anything. Put in a Logger.log('categories: ' + categories); statement at the top of the getTopics(subCategories,categories) function, and I'll bet that it shows nothing.
As a "side note". The doGet() function is using the createTemplateFromFile() method, but there are no scriptlets in your index.html file. The index.html file is not a template. If you were using a template, you wouldn't need to run some of the browser code when the html loads. I'm not saying that it's better to use the scriptlets, or suggesting you do that. But I just wanted you to know what is happening and what your options are.

Get values from multiple selections with querySelectorAll

<!DOCTYPE html>
<html>
<head>
<script>
window.onload = function() {
var data = document.querySelectorAll('span.data-01', 'span.data-02');
for (var i=0;i<len;i++) {
console.log(data[i].className + " " + data[i].childNodes[0].nodeValue)
//var one = parseInt(data[i].childNodes[0].nodeValue);
//var two = parseInt(data[i].childNodes[0].nodeValue);
}
//total = one + two;
//console.log(total);
};
</script>
</head>
<body>
<div class="info">
<span class="data-01">9000</span>
<span class="data-02">6500</span>
</div>
</body>
</html>
How do you put each of these values into a variable to be outputted in the console log?
I want to be able to add values marked by class data-01 + data-02 (15500). For some reason only data-01 is shown in the console.
Answer
querySelectorAll () requires
this
'span.data-01', 'span.data-02'
should be this
'span.data-01, span.data-02'
Just loop through the result and get the nodeValue of the text node:
var data = document.querySelectorAll('span.data-01,span.data-02');
var sum=0;
for (var i=0;i<data.length;i++) {
console.log(data[i].className + " " + data[i].childNodes[0].nodeValue);
sum=sum + parseFloat(data[i].childNodes[0].nodeValue);
}
Or:
var data = document.querySelector('div.info').childNodes;
var sum = 0;
for (var i = 0; i < data.length; i++) {
if (data[i].nodeType == 1) {
console.log(data[i].className + " " + data[i].childNodes[0].nodeValue);
sum = sum + parseFloat(data[i].childNodes[0].nodeValue);
}
}
What about:
var data = document.querySelectorAll('span.data-01, span.data-02');

Categories