Web app - Google sheets - html table with input field - javascript

We have a requirement to track and audit production, essentially we have lots of orders of which we seem to be loosing some of our products on the way (spoils etc).
To stop this we have now placed orders on to google sheets and listed a quantity of how many there should be, an employee then would write in how many was recieved.
On the web app I want to show the table and have a field where the employee can enter the count,
So if I had a google sheet I might have in column A [Product Name] column b [Start Quanity] and in column C [Counted Quantity]
On the web app it will show all 3 columns but allow the user to enter the count into the [Counted Quantity] column.
Is this possible? (Assuming I either need a input field within the html table or an editable table?
Thanks

This will get all of the data in your spread but you can only edit the last column. It's built as a dialog but one could easily change that to a webapp.
I had some problems with scopes so I thought you might need them. If you don't know what do to with these then skip them and come back if you have a problem.
"oauthScopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/script.container.ui"]
ordercounts.gs:
function getOrders() {
var ss=SpreadsheetApp.getActive();
var osh=ss.getSheetByName("Orders");
var org=osh.getDataRange();
var vA=org.getValues();
var rObj={};
var html='<style>th,td{border: 1px solid black}</style><table>';
vA.forEach(function(r,i){
html+='<tr>';
r.forEach(function(c,j){
if(i==0){
html+=Utilities.formatString('<th>%s</th>',c);
}else if(j<r.length-1){
html+=Utilities.formatString('<td>%s</td>', c);
}else{
html+='<td id="cell' + i + j + '">' + '<input id="txt' + i + j + '" type="text" value="' + c + '" size="20" onChange="updateSS(' + i + ',' + j + ');" />' + '</th>';
}
});
html+='</tr>';
});
html+='</table>';
return html;
}
function updateSpreadsheet(updObj) {
var i=updObj.rowIndex;
var j=updObj.colIndex;
var value=updObj.value;
var ss=SpreadsheetApp.getActive();
var sht=ss.getSheetByName("Orders");
var rng=sht.getDataRange();
var rngA=rng.getValues();
rngA[i][j]=value;
rng.setValues(rngA);
var data = {'message':'Cell[' + Number(i + 1) + '][' + Number(j + 1) + '] Has been updated', 'ridx': i, 'cidx': j};
return data;
}
function launchOrdersDialog(){
var userInterface=HtmlService.createHtmlOutputFromFile('orders');
SpreadsheetApp.getUi().showModelessDialog(userInterface, "OrderCounts");
}
orders.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function(){
google.script.run
.withSuccessHandler(function(hl){
console.log('Getting a Return');
$('#orders').html(hl);
})
.getOrders();
});
function updateSS(i,j) {
var str='#txt' + String(i) + String(j);
var value=$(str).val();
var updObj={rowIndex:i,colIndex:j,value:value};
$(str).css('background-color','#ffff00');
google.script.run
.withSuccessHandler(updateSheet)
.updateSpreadsheet(updObj);
}
function updateSheet(data) {
//$('#success').text(data.message);
$('#txt' + data.ridx + data.cidx).css('background-color','#ffffff');
}
console.log('My Code');
</script>
</head>
<body>
<div id="orders"></div>
</body>
</html>
Here's what the tool looks like:
All you have to do is enter the updated count and hit enter and the spreadsheet changes.

Related

How to synchronize every pair of dynamically created inputs?

I'm creating dynamically multiple elements and i want to synchronize specific ones. I write this code to give a view of my problem as simple as i can.
After creating input and append his value i want to have possibility to edit it every time i want.
So if i create multiple iputs of id input0,1,2 etc. and change value of specific one i want to get this value in suitable input. I write function for 1 pair, How can i achieve that for every pair of dynamically created inputs?
$(document).ready(function() {
var a = 0;
$('#add').hide();
$('#generateInput').click(function() {
$('#divArea').append('<input name="input' + a + '">');
$('#generateInput').toggle();
$('#add').toggle();
})
$('#add').click(function() {
$('#divArea').append('<input name="copyInput' + a + '" value="' + $('input[name="input' + a + '"]').val() + '"readonly="readonly"><br />');
$('#add,#generateInput').toggle();
a++;
})
});
//how to make this for all created inputs?
$(document).on('keyup', '[name="input0"]', function() {
$('[name="copyInput0"]').val(this.value);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="divArea"></div>
<button id="generateInput">Generate</button>
<button id="add">Add</button>
You can simply use the onkeyup() for each input you create and get the value inside that function.
var a = 0;
$(document).ready(function() {
$('#add').hide();
$('#generateInput').click(function() {
$('#divArea').append('<input onkeyup="onKeyUp(this)" name="input' + a + '" index="' + a + '">');
$('#generateInput').toggle();
$('#add').toggle();
})
$('#add').click(function() {
$('#divArea').append('<input name="copyInput' + a + '" value="' + $('input[name="input' + a + '"]').val() + '"readonly="readonly"><br />');
$('#add,#generateInput').toggle();
a++;
})
});
//how to make this for all created inputs?
function onKeyUp(input) {
$('input[name="copyInput' + $(input).attr('index') + '"]').val(input.value)
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<div id="divArea">
</div>
<button id="generateInput">
Generate
</button>
<button id="add">
Add
</button>

Dynamic html form data AJAX redirect to google sheets bug

I'm working to send form data from a dynamic user form to a google sheets page. There is a corpus of 140 potential forms, users are shown 20 at random. I'm not getting any errors in the console but the google sheet is not populating. I know that the sheets gs script is OK because the connection worked alright under simpler use cases.
I've included the html and js code that I have below. The website is being rendered fine on my local machine. The images and form substance is working as well.
<!DOCTYPE html>
<body>
<!-- Required JS packages for this project-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script src="jquery-3.3.1.min.js"></script>
<script src="require.js"></script>
<!--Create empty form element -->
<div id = "form_submit"></div>
<!-- JS function to fill form element with 20 hold type questions forms -->
<script>
// Establish file name to hold mapping with two lists and a dict to link elements
var files = ['1.png', '10.png', ..., '98.png', '99.png']
var numWords = ["one", "two", "three",.., "one_hundred_and_fifty"]
var numWordDict = { 1: 'one', ..., 150: 'one_hundred_and_fifty' } // Generate list of 20 random digits that will select holds to be classified
// Create array of twenty random holds
var idx = []
for (var j = 0; j < 20; j++) {
idx.push(Math.floor(Math.random() * 140) + 0)
}
console.log(idx)
// Loop over array and make a form element for each hold within the div element
$(document).ready(function (list) {
for (var i = 0; i < idx.length; i++) {
// retrieve mapped index
var randHoldIdx = idx[i]
// build path to hold image
var holdPath = files[randHoldIdx]
var numb = holdPath.match(/\d/g);
numb = numb.join("");
var colName = numWordDict[numb]
var form_name = 'submit-to-google-sheet' + numb
const scriptURL = 'https://script.google.com/macros/s/AKfycbyhMLuTGNkaNOxeNCOx_t1ERThZT8VEYDcMmiQhj773kIrUuRA/exec'
// Form element contents will be appended into the div element with id = form_submit
$("#form_submit").append(
// html form skeleton for users to select jug,pinch, crimp, pocket or undercling from radio button
// options
"<form name = " + form_name + ">"+
"<input type='radio' name = " +colName + " class=" + String(colName) +" value=1>Jug<br>" +
"<input type='radio' name = " + colName + " class=" + String(colName) +" value=2>Pinch<br>" +
"<input type='radio'name = " +colName + " class=" + String(colName) +" value=3>Crimp<br>"+
"<input type='radio' name = " +colName + " class=" + String(colName) +" value=4>Pocket<br>"+
"<input type='radio' name = " +colName + " class=" + String(colName) +" value=5>Undercling"+
// Submit button for form, close form
"<button type='submit'>Submit!</button></form>"+
// image of climbing hold in question with coordinates to position on moonboard
"<div><img src=labelled_imgs/" +String(holdPath) +" alt='selected hold'></div>");
var form = document.forms[form_name]
window.onload=function(){
form.addEventListener('submit', e => {
e.preventDefault()
fetch(scriptURL, { method: 'POST', body: new FormData(form) })
.then(response => console.log('Success!', response))
.catch(error => console.error('Error!', error.message))
})
}
}
});
</script>
</body>
I suspect that there is something wrong with the event listener. It may be something simple, but I would welcome any suggestions for alternate solutions to this problem! This is a little different than just sending user input from a form to a google sheet as the form contents are changed each time the page is rendered. For context, this is a portion of a custom crowd-sourcing platform. Thanks for any help!
Issues:
You're rewriting the window.onload function each time in the loop for each form. Only the last form's submit event will be disabled onload and be submitted to server.
When you're creating a random array of numbers, there is no guarantee that it will be unique. If two forms end up with the same name, only the first form's submit event will be prevented.
Solution:
Since the form is already appended, directly run the function for each form inside the loop without writing window.onload
var form = document.forms[form_name]
form.addEventListener('submit', e => {
e.preventDefault();
fetch(scriptURL, { method: 'POST'.....
Make Idx unique:
idx = [...new Set(idx)]
I was able to solve the problem by changing the architecture of the page. Instead of using many different forms for each classification task, I used one form that was submitted as a whole.
I have posted the new code below. Feel free to reach out for clarification!
<!DOCTYPE html>
<body>
<!-- Required JS packages for this project-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script src="jquery-3.3.1.min.js"></script>
<script src="require.js"></script>
<!--Create empty form element -->
<div id="form_submit1">
<form id="form_submit" , name="submit_to_sheets">
</form>
</div>
<!-- JS function to fill form element with 20 hold type questions forms -->
<script>
// Establish file name to hold mapping with two lists and a dict to link elements
var files = ['1.png', '10.png',...,'99.png']
var numWords = ["one", "two",...,"one_hundred_and_fifty"]
var numWordDict = {
1: 'one',
2: 'two',
...
150: 'one_hundred_and_fifty'
} // Generate list of 20 random digits that will select holds to be classified
// Create array of twenty random holds
var idx = []
for (var j = 0; j < 20; j++) {
idx.push(Math.floor(Math.random() * 140) + 0)
}
console.log(idx)
// Loop over array and make a form element for each hold within the div element
$(document).ready(function(list) {
for (var i = 0; i < idx.length; i++) {
// retrieve mapped index
var randHoldIdx = idx[i]
// build path to hold image
var holdPath = files[randHoldIdx]
var numb = holdPath.match(/\d/g);
numb = numb.join("");
var colName = numWordDict[numb]
// Form element contents will be appended into the div element with id = form_submit
$("#form_submit").append(
// html form skeleton for users to select jug,pinch, crimp, pocket or undercling from radio button
// options
"<input type='radio' name = " + colName + " class=" + String(colName) + " value=1>Jug<br>" +
"<input type='radio' name = " + colName + " class=" + String(colName) + " value=2>Pinch<br>" +
"<input type='radio'name = " + colName + " class=" + String(colName) + " value=3>Crimp<br>" +
"<input type='radio' name = " + colName + " class=" + String(colName) + " value=4>Pocket<br>" +
"<input type='radio' name = " + colName + " class=" + String(colName) + " value=5>Undercling" +
// image of climbing hold in question with coordinates to position on moonboard
"<div><img src=labelled_imgs/" + String(holdPath) + " alt='selected hold'></div>");
}
// prepend form begining to html outside of for loop
// append end of form to html outside of for loop
});
$("#form_submit").append("<button type='submit'>Submit!</button>");
</script>
<script>
const form = document.forms["submit_to_sheets"]
const scriptURL = 'https://script.google.com/macros/s/AKfycbyhMLuTGNkaNOxeNCOx_t1ERThZT8VEYDcMmiQhj773kIrUuRA/exec'
console.log(form)
console.log("loop")
form.addEventListener('submit', e => {
e.preventDefault()
fetch(scriptURL, {
method: 'POST',
body: new FormData(form)
})
.then(response => console.log('Success!', response))
.catch(error => console.error('Error!', error.message))
})
</script>
</body>
</html>

Accessing Wikipedia API with JSONP

I've been trying for the last few days to make my code work, but I just can't find the problem.
I want to make communication with the Wikipedia server and get their JSON API so I can make a list of items corresponding to the input value of searchInput.
I've been looking into JSONP, finding in the end that I can add "&callback=?" to my API request and that it should work.
Now, even though I've added it, the communication still isn't happening.
I've noticed that the console on codepen.io returns "untitled" for a moment while initializing the code after processing the "#searchInput" input.
Perhaps the problem is in my for...in loop.
Do you have any idea what I should do?
The link to my code: http://codepen.io/nedsalk/pen/zqbqgW?editors=1010
(JQuery is already enabled in the "settings" menu)
If you prefer the .html edition of the code:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Object Oriented JavaScript </title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"> </script>
</head>
<body>
<h1> Wikipedia viewer </h1>
Go random!
<form>
<input type="text" name="searchInput" id="searchInput" placeholder="Search Wikipedia"
onkeydown = "if (event.keyCode == 13)
document.getElementById('submit-button').click()"/>
<input type="submit" id="submit-button"/>
</form>
<div id="list"></div>
<script>
$(document).ready(function() {
$("#submit-button").on("click",function (){
var input=$("#searchInput").val();
$.getJSON('https://en.wikipedia.org/w/api.php?action=query&generator=search&gsrsearch=' + encodeURIComponent(input) + '&prop=extracts&exlimit=10&exintro&exsentences=2&format=json&callback=?',
function(API){
$("#list").empty();
for (var id in API.query.pages)
{if(API.query.pages.hasOwnProperty(id){
$("#list").html('<a target="_blank" href="http://en.wikipedia.org/?curid=' + id + '">'
+'<div id="searchList">'
+ "<h2>" + id.title + "</h2>"
+ "<br>"
+ "<h3>" + id.extract + "</h3>"
+ "</div></a><br>")
}}
})
})
})
</script>
</body>
</html>
You have several issues in your code:
you should hook to the submit event of the form, not the click of the button, and use event.preventDefault() to stop the submission.
you loop through the keys of the returned object and attempt to access properties of those strings, instead of using the keys to access the underlying properties.
you set the html() in each loop, so only the final item will be visible. You should use append() instead.
Try this:
$("form").on("submit", function(e) {
e.preventDefault();
var input = $("#searchInput").val();
$.getJSON('https://en.wikipedia.org/w/api.php?action=query&generator=search&gsrsearch=' + encodeURIComponent(input) + '&prop=extracts&exlimit=10&exintro&exsentences=2&format=json&callback=?', function(response) {
var pages = response.query.pages;
$("#list").empty();
for (var id in pages) {
$("#list").append('<a target="_blank" href="http://en.wikipedia.org/?curid=' + id + '">' +
'<div id="searchList">' +
"<h2>" + pages[id].title + "</h2>" +
"<br>" +
"<h3>" + pages[id].extract + "</h3>" +
"</div></a><br>")
}
});
});
Working example

How to add new row to the table using a button in mvc4 view

I'm trying to add a button to 'add new row' to the table in my mvc view.
First I tried this and it worked.
<script type="text/javascript">
$(document).ready(function () {
function addRow() {
var html = '<tr><td>' +
'<input type="text" id="Text1">' +
'</td><td>' +
'<input type="text" id="Text2">' +
'</td></tr>'
$(html).appendTo($("#table1 > tbody"))
};
$(".BtnAdd").click(addRow);
});
</script>
Then I had to change input type="text" to #Html.TextAreaFor()
So I tried this...but not working
<script type="text/javascript">
$(document).ready(function () {
function addRow() {
var html = '<tr><td>' +
'#Html.TextAreaFor(m => m.schedule1)' +
'</td><td>' +
'#Html.TextAreaFor(m => m.Schedule2)' +
'</td></tr>' +
$(html).appendTo($("#table1 > tbody"))
};
$(".BtnAdd").click(addRow);
});
</script>
Anyone please help me...Sorry if my way of presenting the problem is bad (new to .net)
Is there any other good way? (using for each loop etc)
Thanks

JSon and Jquery Accordion

This is driving me freaking BATTY as hell.
This is essentially what I am trying to accomplish.
You'll see the Json there are a 2 different departments "Office" and "Stockroom"
What I am trying to accomplish is to arrange everyone by the department they are in. The problem with this is that the HTML needs to look something like this
<h3>Section 1</h3>
<div>
<p>
First Paragraph
</p>
<p>
Second Paragraph
</p>
<p>
Third Paragraph
</p>
</div>
But unfortunately I cannot seem to get the </div> tag in the right spot at the end of the last paragraph of each section
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="http://jqueryui.com/themes/base/jquery.ui.all.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://jqueryui.com/ui/jquery.ui.core.js"></script>
<script type="text/javascript" src="http://jqueryui.com/ui/jquery.ui.widget.js"></script>
<script type="text/javascript" src="http://jqueryui.com/ui/jquery.ui.accordion.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var contacts = [{"displayname":"Bruce Lee","email":"Bruce.lee#karate.com","department":"stockroom"},
{"displayname":"Your Momma","email":"Your.Momma#Yourmom.com ","department":"stockroom"},
{"displayname":"Bob","email":"Bob#bob.com ","department":"Office"},
{"displayname":"Cathy","email":"Cathy#Cathy.com ","department":"Office"},
{"displayname":"mike","email":"mike#Cathy.com ","department":"Office"},
{"displayname":"scott","email":"scott#Cathy.com ","department":"Office"}
];
var contacts2 = contacts;
var r = 1;
var lastvalue = 'blah';
for(var i=0; i <=contacts.length; i++)
{
if(contacts[i].department != null)
{
if(lastvalue != contacts[i].department)
{
if(i<1)
{
$('#accordion').append('</div><h3>' + contacts[i].department + '</h3>');
$('#accordion').append('<div><p>' + contacts[i].displayname + '</p>');
}else{
$('#accordion').append('<h3>' + contacts[i].department + '</h3>');
$('#accordion').append('<div><p>' + contacts[i].displayname + '</p>');
}
}else{
$('#accordion').append('<p>' + contacts[i].displayname + '</p>');
}
lastvalue = contacts[i].department;
r++;
}
}
});
$(function() {
$( "#accordion" ).accordion();
});
</script>
</head>
<body>
<div id="contactlist">
<div id="accordion">
</div>
</div>
</body>
</html>
You might want to change this to a jquery each loop and work with json objects directly inside it. The reason you were getting an accordion level each time was due to your loop inserting a h3 every time. I've supplied code to get you pretty much what you need.
edit:
Here is a link to my forked jsfiddle => http://jsfiddle.net/TTV6d/12/
Hope this helps
var departmentlist=new Array();
$.each(contacts, function(i,contact) {
//insert the departments
if (contact.department != null && $('#' + contact.department).length == 0) {
$('#accordion').append('<h3 id='+ contact.department +'>' + contact.department + '</h3>');
departmentlist.push(contact.department);
}
//insert contacts in the accordion
$('#' + contact.department).after('<p>' + contact.displayname + '</p>');
});
$.each(departmentlist, function(i,list) {
$("#" + list).nextUntil("h3").wrapAll("<div></div>");
});
First, be aware that browsers will generally attempt to normalize markup appended to the document: (http://jsfiddle.net/EVjaq/)
$('#container').append('<div><p>Testing</p>'); // no `</div>`
console.log($('#container').html()); // `<div><p>Testing</p></div>`
So, the open <div> in this line will be closed at the end for you, before the next <p> is appended:
$('#accordion').append('<div><p>' + contacts[i].displayname + '</p>');
To avoid this, you can store all of the HTML in a variable, concatenating segments together, and append it to the DOM only once it's done. Or, you can store the <div> and append to that, which can make the conditionals a bit simpler:
var lastvalue = null,
lastdiv = null;
for (var i = 0; i <= contacts.length - 1; i++) {
if (contacts[i].department != null) {
if (lastvalue != contacts[i].department) {
$('#accordion').append('<h3>' + contacts[i].department + '</h3>');
// remember `<div>`
lastdiv = $('<div>').appendTo('#accordion');
}
// append to the `<div>` directly rather than `#accordion`
// also, skip the `else` so you don't have to type this twice
lastdiv.append('<p>' + contacts[i].displayname + '</p>');
lastvalue = contacts[i].department;
r++;
}
}

Categories

Resources