Change which variable is added to in a function - javascript

I'm struggling to understand how I change which variable is being added to in a function.
Essentially, when a user chooses a hotel, it needs to be added to hotelSelection. When they click next, it updates a map with restaurants, and when they choose restaurants, it needs to go into restaurantSelection. That's the bit I'm stuck on, changing it from hotel selection to restaurant selection.
Here's a snippet:
var hotelSelection = "";
var restaurantSelections = "";
var sightSelections = "";
function chooseSelection(resultIndex) {
var locationName = document.getElementById('locationName-' + resultIndex);
hotelSelection = `<div class="input-group" id="Hotel-chosen">
<li class="list-group-item">
<strong>${locationName.innerHTML}</strong><br>`;
var locationRating = document.getElementById('locationRating-' +
resultIndex);
hotelSelection += `rating: ${locationRating.innerHTML}</li>`
console.log("Hotel Selection: " + hotelSelection);
}
Any help would be really appreciated!

This gets to the heart of how a function can communicate. What you are doing is accessing a variable in a higher "closure." This has its good and bad points, and one of the bad points which you're finding now is that it isn't very flexible.
If instead of doing it this way you were able to use the return value of the function, you would have the flexibility to do what you're saying. For example:
var hotelSelection = "";
var restaurantSelections = "";
var sightSelections = "";
function chooseSelection(resultIndex) {
var locationName = document.getElementById('locationName-' + resultIndex);
var selection = `<div class="input-group" id="Hotel-chosen">
<li class="list-group-item">
<strong>${locationName.innerHTML}</strong><br>`;
var locationRating = document.getElementById('locationRating-' +
resultIndex);
selection += `rating: ${locationRating.innerHTML}</li>`
console.log("Hotel Selection: " + hotelSelection);
return selection;
}
If you do this, then when you call the function you just assign the return value to a variable, like this:
hotelSelection = chooseSelection(someIndex);
sightSelections = chooseSelection(someIndex);

Related

How do I add a new value to a Google Sheet from a text field in a Web App and then automatically update the associated dropdown?

WARNING: I'm not a programmer by trade.
Ok. Got the disclaimer out of the way. So this might not be the best way to do this but here is the scenario. I have a dropdown that gets populated via a Google Sheet. The user chooses a selection from the list but this dropdown does not have all of the possible values it could have. There will likely be a time when the user needs a new value added. While I could manually update the spreadsheet as new values are requested that introduces an element of human availability to get this done and I'm not always available.
What I would prefer is a self-serve model. I want to supply the user with a text field where they can enter the new value and submit it to the Google Sheet. Then I would like the dropdown to be updated with the new value for the user to choose.
Now, I realize that I could just submit the value in the new field to the Google Sheet but that will require building a condition to see whether it is the dropdown or text field that has a value in it. I'd also need some type of error handling in case both the dropdown and text field have values. That seems like a bigger headache to program then my ask.
I'm not sure what code you would need to see to help make this work but here is what I think might help.
doGet function
function doGet(e){
var ss = SpreadsheetApp.openById(ssId)
var ws = ss.getSheetByName("External");
var range = ws.getRange("A2:D2");
var valuesArray = [];
for (var i = 1; i <= range.getLastColumn(); i++){
var lastRowInColumn = range.getCell(1, i).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
var list = ws.getRange(2,i,lastRowInColumn-1,1).getValues();
valuesArray.push(list);
}
var userEmail = Session.getActiveUser().getEmail();
var sourceListArray = valuesArray[2].map(function(r){ return '<option>' + r[0] + '</option>'; }).join('');
var productListArray = valuesArray[3].map(function(r){ return '<option>' + r[0] + '</option>'; }).join('');
var tmp = HtmlService.createTemplateFromFile("config");
tmp.productList = productListArray;
return tmp.evaluate();
}
Add to Google Sheet
function userClicked(tagInfo){
var ss = SpreadsheetApp.openById(ssId)
var ws = ss.getSheetByName("Data");
ws.appendRow([tagInfo.email, tagInfo.source, tagInfo.product, new Date()]);
}
Add record
function addRecord(){
var tagInfo = {};
tagInfo.product = document.getElementById("product").value;
google.script.run.userClicked(tagInfo);
var myApp = document.getElementById("source");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
var myApp = document.getElementById("brand");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
var myApp = document.getElementById("product");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
}
How dropdowns are populated in the HTML.
<div class="input-field col s3">
<select id="product" onchange="buildURL()">
<option disabled selected value="">Choose a product</option>
<?!= productList; ?>
</select>
<label>Product</label>
</div>
Need to see anything else? I think it might be relatively easy to add the new value to the column but the tricky part seems to be the update of only that one dropdown and not the entire app. To me it seems like I want to trigger the doGet() function again but only for that specific dropdown. Thoughts?
UPDATE: current code to add new value to dropdown
function addProduct() {
let newProd = document.getElementById("newProduct").value;
google.script.run.withSuccessHandler(updateProductDropdown).addNewProduct(newProd);
document.getElementById("newProduct").value = "";
}
function updateProductDropdown(newProd){
var newOption = document.createElement('option');
newOption.value = newProd;
newOption.text = newProd;
document.getElementById('product').add(newOption);
}
UPDATE2: App Scripts function to add new value to column in spreadsheet
function addNewProduct(newProd){
var columnLetterToGet, columnNumberToGet, direction, lastRow, lastRowInThisColWithData, rng, rowToSet, startOfSearch, valuesToSet;
var ss = SpreadsheetApp.openById(ssId);
var ws = ss.getSheetByName("List Source - External");
lastRow = ws.getLastRow();
//Logger.log('lastRow: ' + lastRow)
columnNumberToGet = 9;//Edit this and enter the column number
columnLetterToGet = "I";//Edit this and enter the column letter to get
startOfSearch = columnLetterToGet + (lastRow).toString();//Edit and replace with column letter to get
//Logger.log('startOfSearch: ' + startOfSearch)
rng = ws.getRange(startOfSearch);
direction = rng.getNextDataCell(SpreadsheetApp.Direction.UP);//This starts
//the search at the bottom of the sheet and goes up until it finds the
//first cell with a value in it
//Logger.log('Last Cell: ' + direction.getA1Notation())
lastRowInThisColWithData = direction.getRow();
//Logger.log('lastRowInThisColWithData: ' + lastRowInThisColWithData)
rowToSet = lastRowInThisColWithData + 1;
valuesToSet = [newProd];
ws.getRange(rowToSet, 9).setValues([valuesToSet]);
return newProd;
}
SOLUTION to Update Materialize Dropdown
function updateProductDropdown(newProd){
newProdOption = document.getElementById('product');
newProdOption.innerHTML += '<option>' + newProd + '</option>';
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems);
}
You can specify a client side callback function if you use google.script.run withSuccessHandler(callback) where your callback could update the list only and not the whole site.
Example:
google.script.run.withSuccessHandler(updateDropdownWidget).updateDropdownList(text_from_input)
Where updateDrownList(text_from_input) is a function in your Apps Script that adds text to the sheet using SpreadsheetApp for example, and returns the "text" to the callback function: updateDropdownWidget(text) which adds a new list item to the HTML drop-down list in your front end.
index.html:
<form>
<label for="newOption">New option for the dropdown:</label>
<input type="text" id="nopt" name="newOption">
<input type="button" value="Submit"
onclick="google.script.run.withSuccessHandler(updateDropdownWidget)
.updateDropdownList(document.getElementById('nopt').value)">
</form>
<label for="cars">Choose a car:</label>
<select name="cars" id="cars">
<?!= values; ?>
</select>
<script>
function updateDropdownWidget(text){
var option = document.createElement('option');
option.value = text;
option.text = text;
document.getElementById('cars').add(option);
}
</script>
Code.gs:
function doGet(e){
var ss = SpreadsheetApp.getActiveSheet();
var lastRow = ss.getDataRange().getLastRow();
var values = ss.getRange(1,1,lastRow,1).getValues();
var valuesArray = [];
for (var i = 0; i < values.length; i++){
valuesArray.push('<option value="'+values[i]+'">' +values[i]+ '</option>');
}
var tmp = HtmlService.createTemplateFromFile("index");
tmp.values = valuesArray;
return tmp.evaluate();
}
function updateDropdownList(text_from_input){
// Log the user input to the console
console.log(text_from_input);
// Write it to the sheet below the rest of the options
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getDataRange().getLastRow();
sheet.getRange(lastRow+1,1).setValue(text_from_input);
// Return the value to the callback
return text_from_input;
}
Here's an example:
In my Stack Over Flow spreadsheet I four buttons which can be used to run any function in 3 script files and every time I load the sidebar it reads the functions in those script files and returns them to each of the select boxes next to each button so that I test functions that I write for SO with a single click and I can select any function for any button. Here's the Javascript:
$(function(){//JQuery readystate function
google.script.run
.withSuccessHandler(function(vA){
let idA=["func1","func2","func3","func4"];
idA.forEach(function(id){
updateSelect(vA,id);
});
})
.getProjectFunctionNames();
})
Here is GS:
function getProjectFunctionNames() {
const vfilesA=["ag1","ag2","ag3"];
const scriptId="script id";
const url = "https://script.googleapis.com/v1/projects/" + scriptId + "/content?fields=files(functionSet%2Cname)";
const options = {"method":"get","headers": {"Authorization": "Bearer " + ScriptApp.getOAuthToken()}};
const res = UrlFetchApp.fetch(url, options);
let html=res.getContentText();
//SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), "Project Functions");
let data=JSON.parse(res.getContentText());
let funcList=[];
let files=data.files;
files.forEach(function(Obj){
if(vfilesA.indexOf(Obj.name)!=-1) {
if(Obj.functionSet.values) {
Obj.functionSet.values.forEach(function(fObj){
funcList.push(fObj.name);
});
}
}
});
//SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(funcList.join(', ')), "Project Functions");
return funcList;//returns to withSuccessHandler
}
Image:
Animation:

text string output stops after first space, js/html

I apologize in advance, this is the first Stack Overflow question I've posted. I was tasked with creating a new ADA compliant website for my school district's technology helpdesk. I started with minimal knowledge of HTML and have been teaching myself through w3cschools. So here's my ordeal:
I need to create a page for all of our pdf and html guides. I'm trying to create a somewhat interactable menu that is very simple and will populate a link array from an onclick event, but the title="" text attribute drops everything after the first space and I've unsuccessfully tried using a replace() method since it's coming from an array and not static text.
I know I'm probably supposed to use an example, but my work day is coming to a close soon and I wanted to get this posted so I just copied a bit of my actual code.
So here's what's happening, in example 1 of var gmaildocAlt the tooltip will drop everything after Google, but will show the entire string properly with example 2. I was hoping to create a form input for the other helpdesk personnel to add links without knowing how to code, but was unable to resolve the issue of example 1 with a
var fix = gmaildocAlt.replace(/ /g, "&nb sp;")
//minus the space
//this also happens to break the entire function if I set it below the rest of the other variables
I'm sure there are a vast number of things I'm doing wrong, but I would really appreciate the smallest tip to make my tooltip display properly without requiring a replace method.
// GMAIL----------------------------
function gmailArray() {
var gmaildocLink = ['link1', 'link2'];
var gmaildocTitle = ["title1", "title2"];
var gmaildocAlt = ["Google Cheat Sheet For Gmail", "Google 10-Minute Training For Gmail"];
var gmailvidLink = [];
var gmailvidTitle = [];
var gmailvidAlt = [];
if (document.getElementById("gmailList").innerHTML == "") {
for (i = 0; i < gmaildocTitle.length; i++) {
arrayGmail = "" + gmaildocTitle[i] + "" + "<br>";
document.getElementById("gmailList").innerHTML += arrayGmail;
}
for (i = 0; i < gmailvidTitle.length; i++) {
arrayGmail1 = "";
document.getElementById("").innerHTML += arrayGmail1;
}
} else {
document.getElementById("gmailList").innerHTML = "";
}
}
<div class="fixed1">
<p id="gmail" onclick="gmailArray()" class="gl">Gmail</p>
<ul id="gmailList"></ul>
<p id="calendar" onclick="calendarArray()" class="gl">Calendar</p>
<ul id="calendarList"></ul>
</div>
Building HTML manually with strings can cause issues like this. It's better to build them one step at a time, and let the framework handle quoting and special characters - if you're using jQuery, it could be:
var $link = jQuery("<a></a>")
.attr("href", gmaildocLink[i])
.attr("title", gmaildocAlt[i])
.html(gmaildocTitle[i]);
jQuery("#gmailList").append($link).append("<br>");
Without jQuery, something like:
var link = document.createElement("a");
link.setAttribute("href", gmaildocLink[i]);
link.setAttribute("title", gmaildocAlt[i]);
link.innerHTML = gmaildocTitle[i];
document.getElementById("gmailList").innerHTML += link.outerHTML + "<br>";
If it matters to your audience, setAttribute doesn't work in IE7, and you have to access the attributes as properties of the element: link.href = "something";.
If you add ' to either side of the variable strings then it will ensure that the whole value is read as a single string. Initially, it was assuming that the space was exiting the Title attribute.
Hope the below helps!
UPDATE: If you're worried about using apostrophes in the title strings, you can use " by escaping them using a . This forces JS to read it as a character and not as part of the code structure. See the example below.
Thanks for pointing this one out guys! Sloppy code on my part.
// GMAIL----------------------------
function gmailArray() {
var gmaildocLink = ['link1', 'link2'];
var gmaildocTitle = ["title1", "title2"];
var gmaildocAlt = ["Google's Cheat Sheet For Gmail", "Google 10-Minute Training For Gmail"];
var gmailvidLink = [];
var gmailvidTitle = [];
var gmailvidAlt = [];
if (document.getElementById("gmailList").innerHTML == "") {
for (i = 0; i < gmaildocTitle.length; i++) {
var arrayGmail = "" + gmaildocTitle[i] + "" + "<br>";
document.getElementById("gmailList").innerHTML += arrayGmail;
}
for (var i = 0; i < gmailvidTitle.length; i++) {
var arrayGmail1 = "";
document.getElementById("").innerHTML += arrayGmail1;
}
} else {
document.getElementById("gmailList").innerHTML = "";
}
}
<div class="fixed1">
<p id="gmail" onclick="gmailArray()" class="gl">Gmail</p>
<ul id="gmailList"></ul>
<p id="calendar" onclick="calendarArray()" class="gl">Calendar</p>
<ul id="calendarList"></ul>
</div>

JQuery multiple input fields of each row keyup function not working

Hello I am trying to make my jquery code in working order but its not working at all, I don't know whats a problem behind it but it contains multiple text boxes in multiple rows, each row calculates its own sum
Here is Fiddle link
Here is my Code
$(document).ready(function(){
$('.employee input[type="text"]').keyup(function() {
var basic_salary = parseInt($('input[name^=txtMonthlyRate]').val());
var advance_salary = parseInt($('input[name^=txtAdvance]').val());
var recover_comm = parseInt($('input[name^=txtRecovery]').val());
var sales_comm = parseInt($('input[name^=txtSales]').val());
var deduction_salary = parseInt($('input[name^=txtDeduction]').val());
var adjustment_salary = parseInt($('input[name^=txtAdjustment]').val());
var total_sum = ((basic_salary+recover_comm+sales_comm) - (deduction_salary + advance_salary)) + adjustment_salary;
$('input[name^=txtTotal]').val(total_sum);
console.log(total_sum)
);
});
The txtSales1, txtDeduction1, txtAdjustment1 variables are camel cased in your javascript, but not on the html input name. So these return NaN.
UPDATE Also, you need to set the context of what you're referring to using the second parameter of a selector function:
$('.employee input[type="text"]').keyup(function(e) {
var $scope = $(this).closest('.employee');
var basic_salary = parseInt($('input[name^=txtMonthlyRate]', $scope).val());
var advance_salary = parseInt($('input[name^=txtAdvance]', $scope).val());
var recover_comm = parseInt($('input[name^=txtRecovery]', $scope).val());
var sales_comm = parseInt($('input[name^=txtSales]', $scope).val());
var deduction_salary = parseInt($('input[name^=txtDeduction]', $scope).val());
var adjustment_salary = parseInt($('input[name^=txtAdjustment]', $scope).val());
var total_sum = ((basic_salary+recover_comm+sales_comm) - (deduction_salary + advance_salary)) + adjustment_salary;
$('input[name^=txtTotal]', $scope).val(total_sum);
});
The txttotal1 needs to be changed to txtTotal1
The fiddle needs a closing }

Dynamically generated HTML selectedIndex returns null

I am trying to refactor old code without completely redoing the program.
I have objects that are strategically named to be a value of the string from vendor. (vendor = "Ansys" or vendor = "Cadence")
var Ansys = {key:'ansyskeys', loaded:0, display: "none", otherkey: 'anotherkey'};
var Cadence = {key:"cdskeys", loaded:0, display: "none", otherkey: 'cotherkey'};
My previous HTML code that was static and had many entries that looked like:
<div id="ansyskeys" style="display:none">
<select id="anotherkey" size="5" onchange="selectOther('anotherkey')"></select>
</div>
To replace this, I made a function -ignore the use of eval, security is no concern:
function createDiv()
{
var vendorKey = eval(vendor).key;
var otherVendorKey = eval(vendor).otherkey;
var myDiv = document.createElement('div');
var html = '<select id="' + otherVendorKey + '" size="4" onchange="selectOther('+ otherVendorKey + ')"></select>';
myDiv.innerHTML = html;
myDiv.id = vendorKey;
document.body.appendChild(myDiv);
}
I am recieving my desired result, however, when I try to use selectedIndex in the function selectOther, it appears that mk is null.
function selectOther(wid)
{
var mk = document.getElementById(wid);
alert(mk);
var index = mk.selectedIndex;
key = mk.options[index].value;
setKey ();
getKeyStats ();
}
The HTML seems to be working, but doesnt seem to recognize the id from wid. Any help would be much appreciated.

how to get username via checked checkbox with javascript or jquery?

i
HTML
<div id="notApprovedUsers">
</div><button onclick="approveUsers()">Approve</button>
</div>
i like to get checked users in parameter userList to work with.
here is javascript there me generating list with users and checkboxes.
i like to approve just the checked one's of course!
JavaScript
function getNotAssignedUsers() {
server.getUsersByGroup("1eb33e30-c355-467f-af3c-e7d0b4a1fgt5").then(function (userDetails) {
debugger;
for (var i = 0; i < userDetails.length; i++)
{
var vorname = userDetails[i].firstName;
var nachname = userDetails[i].lastName;
var newCheckBox = document.createElement('input');
newCheckBox.type = 'checkbox';
newCheckBox.id = "0"+i;
document.getElementById("notApprovedUsers").appendChild(newCheckBox);
var newElement = document.createElement('div');
newElement.id = i;
newElement.className = "notApprovedUsers";
newElement.innerHTML = vorname + " " + nachname;
document.getElementById("notApprovedUsers").appendChild(newElement);
}
});
}
HERE in userList I need to read just a checked users..
function approveUsers(userList)
{
var user1 = document.getElementById("00").checked;
var user2 = document.getElementById("01").checked;
var user3 = document.getElementById("02").checked;
alert(user1 || user2 || user3);
}
You want something like this then. There may be errors as I havent tested
var names = [];
$('input[type=checkbox]:checked').each(function(index, value){
var name = $(value).next("div").html();
names.push(name);
});
Then do something with the names array
Edit - See jsfiddle http://jsfiddle.net/vpg3r/3/
I think the best solution for you here is to use jQuery. You can use something like:
$('#notApprovedUsers input[type=checkbox]:checked')
to get all the elements that are checked, and work with them.
I've created a JSFiddle for you to demonstrate how to implement the behavior that I'm describing. You can see it in this link.

Categories