I have figured out how to append text boxes and set class as autocomplete therefore setting default values as the dynamic list generated in an avaliableTag function on the google app script side. I need to get each appended text box value back to the google app script side so the end user can submit the data and a new row of data will be appended to the google sheet. Here is my html code
<label for="units" style="font-size:125%;"><b>Number of items on Ticket</b></label>
<input type="text" name="units" id="units">
<!-- specified units by user-->
<button id = 'numitems' onclick = "getUnits()">Add items </button>
<!-- button that runs function to append appropriate # of boxes -->
</div>
<button id = 'submit' type = 'submit'name = "action">Submit </button>
Here is my google script code (left out doGet and HTML Service) these functions are what the user will submit to google sheet and the function that generates autocomplete options. Still need to get userInfo.MEDS
function userClicked(userInfo){
var ss = SpreadsheetApp.openByUrl('someURL');
var ws= ss.getSheetByName('Sheet1')
var user = Session.getActiveUser();
var timestamp = Utilities.formatDate(new Date(), 'CST', 'MM/dd/yyyy HH:mm:ss')
Logger.log(userInfo)
ws.appendRow([user,userInfo.id,userInfo.ticket,userInfo.items,userInfo.MEDS,timestamp]);
}
function getAvailableTags() {
var ss = SpreadsheetApp.openById("someId");
var s = ss.getSheetByName("someSheet");
var data= s.getRange("A2:A").getValues();
var headers = 1;
var tagColumn = 0;
var availableTags = [];
for (var row=headers; row < data.length; row++) {
availableTags.push(data[row][tagColumn]);
}
return( availableTags );
}
and finally here is the js/jquery side
var x=1
function appendRow()
{
var d = document.getElementById('left-col');
d.innerHTML += "<input type='text'class = 'autocomplete' id='tst"+ x++ +"'><br >";
}
function getUnits() {
var units = $("#units").val();
x=1
for (var count = 1; count < units; count++) {
$("<input type='text'class = 'autocomplete' id='tst"+ x++ +"'><br >").appendTo("#left-col");
}
var mednum = 0
$("#left-col").append("<input type='text'class = 'autocomplete' id='tst"+ x++ +"'>")
;
}
$(function() {
google.script.run.withSuccessHandler(buildTagList)
.getAvailableTags();
});
function buildTagList(availableTags) {
$( ".autocomplete" ).autocomplete({
source: availableTags
});
}
$('#submit').on('click', function (){
$('.autocomplete').each(function() {
var med = $(this).val();
console.log(med);
});
});
window.onload=function(){
document.getElementById('submit').addEventListener('click',buttonClick);
function buttonClick() {
var userInfo = {};
userInfo.Id = document.getElementById('ptid').value
userInfo.ticket = document.getElementById('ticket').value
userInfo.items = document.getElementById('items').value
}}
I need something that will take value of each appended box and let me store it in the userInfo object so it can be passed back to the gs side
You can use google.script.run to run a function in code.gs side and send the form object [1]. Also, you should prevent the default behavior for when the form is submitted:
function buttonClick() {
var userInfo = {};
userInfo.Id = document.getElementById('ptid').value
userInfo.ticket = document.getElementById('ticket').value
userInfo.items = document.getElementById('items').value
google.script.run.userClicked(userInfo)
}
$("#formID").submit(function(e){
e.preventDefault();
});
[1] https://developers.google.com/apps-script/guides/html/communication#forms
Related
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:
I have a gridview using devexpress tools that is populated on page load. When I select a row I have button that will allow me to edit the information in that row by popping up an edit box that allows me to change the information. The issue I am having is when they click that button the data that was behind the gridivew could have changed so I want to be able to query the database again (using some parameters from the selected row) when that edit button is clicked.
Here is the query that is ran when the 'edit' button is clicked.
function ShowPopupEditInventory() {
$.when(getFocusedInventory()).then(function (x) {
popupControlEditInventory.Show();
});
function getFocusedInventory(s, e) {
grid.GetRowValues(grid.GetFocusedRowIndex(), 'StorageLocation;LP;Sku_Alpha;LotCode;ExpirationDate;FIFOReferenceDate;ManufactureDate;InventoryStatus;SellableUnitQuantity;ReceiveDate;InventoryDetailID;Area', getFocusedInventoryValues);
}
function getFocusedInventoryValues(values) {
var fStorageLocation = values[0];
var fLP = values[1];
var fSku_Alpha = values[2];
var fLotCode = values[3];
var fExpirationDate = values[4];
var fFIFOReferenceDate = values[5];
var fManufactureDate = values[6];
var fInventoryStatus = values[7];
var fSellableUnitQuantity = values[8];
var fReceiveDate = values[9];
var fInventoryDetailID = values[10];
var fArea = values[11];
editInventoryStorageLocation.SetText(fStorageLocation);
editInventoryLP.SetText(fLP);
editInventoryItem.SetText(fSku_Alpha);
editInventoryQty_OldValue.SetText(fSellableUnitQuantity);
editInventorySts_OldValue.SetText(fInventoryStatus);
editInventoryLot_OldValue.SetText(fLotCode);
txtEditInventoryLot.SetText(fLotCode);
$(".editInventoryLot").val(fLotCode);
editInventoryStatus.SetValue(fInventoryStatus)
editInventoryUnitQuantity.SetText(fSellableUnitQuantity);
editInventoryDTL_No.SetText(fInventoryDetailID);
editInventoryNotes.SetText('');
$(".editInventoryAdjustmentCode").prop("selectedIndex", 0);
editInventoryArea.SetText(fArea);
editInventoryLot.Focus();
btnOKEditInventory.SetEnabled(true);
}
}
I have a JQuery function that fetches and displays a page worth of images through the use of JSON files. I want to display the next set of images upon a button click, but that requires adding on a short string to the request url, which is found and stored in a var when I first run the script. I need to call this JQuery function again and pass the string var to it (lastId in code below). I am an utter noob with JavaScript in general and don't know how to go about doing that.
Here is a full version of the code:
$(function runthis(un){
var lastId;
un = typeof un !== 'undefined' ? un : "";
$('#domainform').on('submit', function(event){
event.preventDefault();
$('#content').html('<center><img src="img/loader.gif" alt="loading..."></center>');
//var lastId;
var domain = $('#s').val();
var newdomain = domain.replace(/\//g, ''); // remove all slashes
var requrl = "http://www.reddit.com/r/";
var getmore;
getmore = "?after=t3_"+un;
var fullurlll = requrl + domain + ".json" + getmore;
$.getJSON(fullurlll, function(json){
var listing = json.data.children;
var html = '<ul class="linklist">\n';
for(var i=0, l=listing.length; i<20; i++) {
var obj = listing[i].data;
var votes = obj.score;
var title = obj.title;
var subtime = obj.created_utc;
var thumb = obj.thumbnail;
var subrdt = "/r/"+obj.subreddit;
var redditurl = "http://www.reddit.com"+obj.permalink;
var subrdturl = "http://www.reddit.com/r/"+obj.subreddit+"/";
var exturl = obj.url;
var imgr = exturl;
var imgrlnk = imgr.replace("target=%22_blank%22","");
var length = 14;
var myString = imgrlnk;
var mycon = imgrlnk;
var end = mycon.substring(0,14);
myString.slice(-4);
var test1 = myString.charAt(0);
var test2 = myString.charAt(1);
var timeago = timeSince(subtime);
if(obj.thumbnail === 'default' || obj.thumbnail === 'nsfw' || obj.thumbnail === '')
thumb = 'img/default-thumb.png';
if(end == "http://i.imgur" ){
$("#MyEdit").html(exturl);
html += '<li class="clearfix">\n';
html += '<img src="'+imgrlnk+'" style="max-width:100%; max-height:750px;">\n';
html += '</li>\n';
html += '<div class="linkdetails"><h2>'+title+'</h2>\n';
/*html += '<p class="subrdt">posted to '+subrdt+' '+timeago+'</p>'; /*'+test1+test2+'*/
html += '</div></li>\n';
}
if (listing && listing.length > 0) {
lastId = listing[listing.length - 1].data.id;
} else {
lastId = undefined;
}
} // end for{} loop
htmlOutput(html);
}); // end getJSON()
}); // end .on(submit) listener
function htmlOutput(html) {
html += '</ul>';
$('#content').html(html);
}
});
The way you currently are executing the function run this doesn't ever leave you a handle to that function. This means it only really exists in the context of document.ready (what $(function()) is a shortcut for).
What you want to do instead is to keep a reference to this function for later use.
If you want to be able to put it directly into an onclick='' you will need to put the function in global,
eg:
var myFunction = function() { /*Stuff here*/}
$(myFunction)
this declares a function called myFunction and then tells jQuery to execute it on document ready
Global is generally considered pretty naughty to edit. One slightly better option would be to assign the click to the button inside your javascript
eg:
$(function(){
var myFunction = function() { /*Stuff here*/}
myFunction(); //call it here
$('#my-button-id').click(myFunction);//attach a click event to the button
)
This means that the function myFunction only exists in the scope of your document.ready, not in global scope (and you don't need onclick='' at all)
tTo add listener on some event you can use live('click',function(){}) Like yhis:
<div id="my-button">some content</div>
<script type="text/javascript">
$('#my-button').live('click',function(){
//your code
})
</script>
I have created a page containing a text-area field and few check boxes, from where user can write many domain names in each line in text-area field, and then can choose different domain type through check-boxes. then user clicks on submit button which is redirected to bulk domain search page ?
Link to page where I'm trying to do this is --
http://www.ailogica.com/wp/packages/
I tried to create a simple submit button, but that does not work, then I wrote following code to submit the data by calling a function --
<script type="text/javascript">
function alerttlds() {
jQuery.noConflict();
var i = 0;
var j = 0;
var values = new Array();
var tld = new Array();
var bulkdomains = new Array;
jQuery.each(jQuery("input[name='tld[]']:checked"), function() {
tld[j++] = jQuery(this).val();
});
for(var k = 0; k < tld.length; k++) {
var lines = jQuery('textarea[name=sld]').val().split('\n');
jQuery.each(lines, function(){
bulkdomains[i++] = this+tld[k];
});
}
//alert(bulkdomains.join("\n"));
document.getElementById('bulkdomains').value = bulkdomains.join("\n");
document.forms["bulkchecks"].submit();
}
</script>
Here is my code, I don't understand what's wrong.
<script type="text/jquery">
function gettotalAdult()
{
//Assume form with id="fsd-bucket-calc"
var theForm = document.forms["fsd-bucket-calc"];
//Get a reference to the # of Adults & Children
var quantity = theForm.elements["totalAdult"];
var caloriesAdult = theForm.elements["caloriesAdult"];
var adultcalTotal=0;
//If the totalAdult is not blank
if(totalAdult.value!="")
{
adultcalTotal = parseInt(totalAdult.value)*parseInt(caloriesAdult.value);
}
return adultcalTotal;
}
function gettotalChild()
{
//Assume form with id="fsd-bucket-calc"
var theForm = document.forms["fsd-bucket-calc"];
//Get a reference to the # of Children
var totalChild = theForm.elements["totalChild"];
var caloriesChild = theForm.elements["caloriesChild"];
var childcalTotal=0;
//If the totalChild is not blank
if(totalChild.value!="")
{
childcalTotal = parseInt(totalChild.value)*parseInt(caloriesChild.value);
}
return childcalTotal;
}
function gettotalCalories()
{
//Here we get the total calories by calling our function
//Each function returns a number so by calling them we add the values they return together
var totalCalories = gettotalAdult() + gettotalChild();
//display the result
document.getElementById('total-req-cal').innerHTML = "The total required calories are "+totalCalories;
}
</script>
This is my HTML:
<input type="text" name="totalAdult" id="totalAdult" onkeyup="gettotalCalories()" />
This is my error:
gettotalCalories is not defined
If it helps, the script is in the head of a WordPress page. Does anyone see what I'm doing wrong?
You have <script type="text/jquery"> you may need <script type="text/javascript"> instead.