How do I run Server-side functions using HtmlService - javascript

I am new to programming and I am trying to wire up a couple of buttons with jQuery using Google-apps-script. I have a spread sheet and a menu added to it the opens a dialog box from HtmlService. In the dialog box I have two buttons, one closes the dialog the other executes a server function, which for now only writes "hello world to cell a1. The "close" button works perfectly, however the "update" doesn't seem to do anything. I'm not exactly sure how to debug the client-side.
<script>
$(document).ready(function(){
$("#update").click(function (){
var params = {}
params.url = $("#url").val()
params.owner = $("#owner").val()
params.type = type
google.script.run.update(params);
});
$("#close").click(function(){
// This one works. why not the "update" button???
google.script.host.close()
})
})
</script>
<title>AJAXtabs.html</title>
</head>
<body>
<div id="content">
<table border="1">
<tr>
<th><?= type ?>URL</th>
<td><input type="text" id="url" name="url"></td>
</tr>
<tr>
<th>New Owner email</th>
<td><input type="text" id="ownerEmail" name="ownerEmail"></td>
</tr>
<tr>
<td colspan="2" id="buttonRow" ><button id="update" type="button" >Update</button><button id="close" type="button">Close</button></td>
</tr>
</table>
</div>
<div id="message">
</div>
</body>
</html>
Code.gs excerpt
function update(params){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var row = sheet.getLastRow()
var col = sheet.getLastColumn()
sheet.getRange('a1').setValue('Hello world!!')
}
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
// When the user clicks on "addMenuExample" then "Menu Entry 1", the function function1 is
// executed.
menuEntries.push({name: "Set file", functionName: "fileUi"});
menuEntries.push(null); // line separator
menuEntries.push({name: "Set Folder", functionName: "folderUi"});
ss.addMenu("Setters", menuEntries);
}
function fileUi(){
var htmlApp = HtmlService.createTemplateFromFile('View template')
htmlApp.type = 'File';
SpreadsheetApp.getActiveSpreadsheet().show(htmlApp.evaluate().setHeight(300).setTitle('Chan ge Owner'));
}
function folderUi(){
var htmlApp = HtmlService.createTemplateFromFile('View template')
htmlApp.type = 'Folder'
SpreadsheetApp.getActiveSpreadsheet().show(htmlApp.evaluate());
}

Below are modified versions of your html and gs files, in which both buttons work. I believe that the only thing that needed to change was the inclusion of the jQuery library.
Debugging
Generally speaking, the best place to debug your client-side functions is in the debugger / IDE, using the techniques appropriate there. You may find some ideas that help you in this tutorial, and these answers:
Stepping through code in Google Apps Script (equivalent VBA-GAS )
How can I test a trigger function in GAS?
To support debugging, this script relies on Peter Herrmann's BetterLog library. You will need to add that to your project, by "Resources - Manage Libraries...". With it, plus the helper function included below, you will have an effective way to log operations of both your client and server side functions. (Since you're using a spreadsheet already, you can log to it... the utility will create a new tab.)
The additional use of BetterLog gives you a way to trace execution across multiple platforms or environments, with better history keeping than the built-in Logger. This example is barely scratching the surface of what that utility does - but it's enough for most purposes!
Various log messages have been left in place, to illustrate.
Example Logs
2013-07-31 00:02:17:332 -0400 000128 INFO in ready
2013-07-31 00:02:17:419 -0400 000094 INFO In html script
2013-07-31 00:02:23:508 -0400 000178 INFO in update.click
2013-07-31 00:02:24:081 -0400 000163 INFO in update (server)
2013-07-31 00:02:24:104 -0400 000186 INFO {"url":"adsfasdfsad","owner":null,"type":null}
2013-07-31 00:02:24:166 -0400 000248 INFO done update (server)
2013-07-31 00:03:14:355 -0400 000248 INFO in close.click
Code.gs
Logger = BetterLog.useSpreadsheet('--Spreadsheet-ID--');
/**
* Make BetterLogger available to client-side scripts, via
* google.script.run.log(string).
*/
function log(string) {
Logger.log(string);
}
function update(params){
Logger.log('in update (server)');
Logger.log(JSON.stringify(params));
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var row = sheet.getLastRow()
var col = sheet.getLastColumn()
sheet.getRange('a1').setValue('Hello world!!')
Logger.log('done update (server)');
}
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
// When the user clicks on "addMenuExample" then "Menu Entry 1", the function function1 is
// executed.
menuEntries.push({
name: "Set file",
functionName: "fileUi"
});
menuEntries.push(null); // line separator
menuEntries.push({
name: "Set Folder",
functionName: "folderUi"
});
ss.addMenu("Setters", menuEntries);
}
function fileUi() {
var htmlApp = HtmlService.createTemplateFromFile('View template')
htmlApp.type = 'File';
var html = htmlApp.evaluate()
.setSandboxMode(HtmlService.SandboxMode.NATIVE)
.setHeight(300)
.setTitle('Change Owner');
SpreadsheetApp.getActiveSpreadsheet().show(html);
}
function folderUi() {
var htmlApp = HtmlService.createTemplateFromFile('View template')
htmlApp.type = 'Folder'
var html = htmlApp.evaluate()
.setSandboxMode(HtmlService.SandboxMode.NATIVE)
.setHeight(300)
.setTitle('Change Owner');
SpreadsheetApp.getActiveSpreadsheet().show(html);
}
View template.html
This has been restructured as per the best practices, and of course log messages are included.
<div id="content">
<table border="1">
<tr>
<th><?= type ?>URL</th>
<td><input type="text" id="url" name="url"></td>
</tr>
<tr>
<th>New Owner email</th>
<td><input type="text" id="ownerEmail" name="ownerEmail"></td>
</tr>
<tr>
<td colspan="2" id="buttonRow" >
<button id="update" type="button" >Update</button>
<button id="close" type="button">Close</button>
</td>
</tr>
</table>
</div>
<div id="message">
</div>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script>
google.script.run.log("In html script");
$(document).ready(function(){
google.script.run.log("in ready");
$("#update").click(function (){
google.script.run.log("in update.click");
var params = {}
params.url = $("#url").val()
params.owner = $("#owner").val()
params.type = type
google.script.run.update(params);
});
$("#close").click(function(){
google.script.run.log("in close.click");
google.script.host.close()
})
})
</script>

Related

Save the email ID of the user filling the form

I have a Google Form to collect information from my workers working in remote locations
Emp No *
Punch *
Customer details / mode or travel
The data goes into a Google spreadsheet with the below structure
Timestamp Emp No Punch Remark Name GeoCode GeoAddress Email
I am able to capture the GPS co-ordinates of the user by the below script. I made a web app (anyone even anonymous can run) and asked the user to click the link.
What I am not able to do :
I want to save the email ID (or emp no) of the user filling the form. But the email ID is not getting captured into the form. If I fill the form, the email ID is captured. For other users it is not captured. I don't want all the users to authenticate the script (to run the script as the logged in user). It must be captured by some other way. Is it possible?
If the GPS is not captured (it is empty), I want to display a different message in the HTML page. How to do it?
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile("Index");
}
//
function getLoc(value) {
var destId = FormApp.getActiveForm().getDestinationId() ;
var ss = SpreadsheetApp.openById(destId) ;
var respSheet = ss.getSheetByName("Location");
var numResponses = respSheet.getLastRow();
var currentemail = Session.getActiveUser().getEmail();
var c=value[0]; var d=value[1];
var e=c + "," + d ;
//respSheet.getRange(numResponses,6).setValue(e);
//respSheet.getRange(numResponses,8).setValue(currentemail);
var response = Maps.newGeocoder().reverseGeocode(value[0], value[1]);
var f= response.results[0].formatted_address;
//respSheet.getRange(numResponses,7).setValue(f);
respSheet.getRange(numResponses,6,1,3 ).setValues([[ e, f, currentemail ]]);
}
//
index.html
<!DOCTYPE html>
<html>
<script>
(function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
}
})()
function showPosition(position){
var a= position.coords.latitude;
var b= position.coords.longitude;
var c=[a,b]
getPos(c)
function getPos(value){
google.script.run.getLoc(value);
}
}
</script>
<body>
<p>Please ensure your GPS is on to record your location. You can generate the report from website to check. Pl. close this window (version 3)</p>
</body>
</html>
From the question
I want to save the email ID (or emp no) of the user filling the form. But the email ID is not getting captured into the form. If I fill the form, the email ID is captured. For other users it is not captured. I don't want all the users to authenticate the script (to run the script as the logged in user). It must be captured by some other way. Is it possible?
On a web application created using Google Apps Script to automatically get the user email ID you could set your web application to be executed as the user running the application instead being executed as you but if don't want to use this feature then you have to set your own authentication process.
From the question
If the GPS is not captured (it is empty), I want to display a different message in the HTML page. How to do it?
Use a JavaScript conditional expression
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
alert('Can\'t get the position');
}
})()
function showPosition(position){
var a= position.coords.latitude;
var b= position.coords.longitude;
var c=[a,b];
getPos(c);
function getPos(value){
google.script.run.getLoc(value);
}
}
The above code uses alert but you could use the DOM.
Resources
Web Apps | Google Apps Script
Document Object Model (DOM)
I was able to make a complete solution without any google form (just HTML) and managed to display an alert message also. The "Login" is still not possible.
Code.gs
It runs the form and saves the answers in the required columns into google sheet.
It runs faster than google form and "Submit" has to be clicked only once.
As the saving happens by "append row", the jumbling of data (between rows) which was happening in my earlier method is avoided.
/* #Include JavaScript and CSS Files */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
/* #Process Form */
function processForm(formObject) {
var url = "https://docs.google.com/spreadsheets/d/...../edit#gid=52499297";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Location");
var response = Maps.newGeocoder().reverseGeocode(formObject.lat, formObject.long);
var address= response.results[0].formatted_address;
ws.appendRow(
[
new Date(),
formObject.empno,
formObject.punch,
formObject.rem,
"",
formObject.lat+","+formObject.long,
address
]
);
}
Index.html
This has the questions.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<?!= include('JavaScript'); ?>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-6">
<form id="myForm" onsubmit="handleFormSubmit(this);">
<p class="h4 mb-4 text-left">Record Attendance and Location</p>
<div class="form-group">
<label for="empno">Emp No - Click to see list</label>
<input type="number" class="form-control" id="empno" name="empno" min="1" max="9999999" required>
</div>
<div class="form-group">
<label for="punch">Punch (Select one)</label>
<select class="form-control" id="punch" name="punch" required>
<option selected disabled hidden style='display: none' value=''></option>
<option value="In">In</option>
<option value="Out">Out</option>
<option value="Started">Started</option>
<option value="Reached">Reached</option>
</select>
</div>
<div class="form-group">
<label for="rem">Remark</label>
<input type="text" class="form-control" id="rem" name="rem">
</div>
<div class="form-group">
<input type="hidden" class="form-control" id="lat" name="lat">
<input type="hidden" class="form-control" id="long" name="long">
</div>
<button type="submit" class="btn btn-primary btn-block">Submit</button>
</form>
<div id="output"></div>
</div>
</div>
</div>
</body>
</html>
JavaScript.html
This processes the answers
<script>
function showPosition() {
navigator.geolocation.getCurrentPosition(showMap);
}
function showMap(position) {
// Get location data
var lat = position.coords.latitude;
var geo1 = document.getElementById("lat");
geo1.value = lat;
var long = position.coords.longitude;
var geo2 = document.getElementById("long");
geo2.value = long;
}
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
window.addEventListener('load', showPosition);
function handleFormSubmit(formObject) {
google.script.run.processForm(formObject);
document.getElementById("myForm").reset();
alert('Data saved successfully');
}
</script>

Excel upload, store it into database using PHP

I'm developing a web application.My App is using Javascript, PHP, HTML. I already done apply code to upload xlsx , attach it on screen .
Here's my Code
<script type="text/javascript" src="simple-excel.js"></script>
<table width=50% align="left" border=0 STYLE="border-collapse:collapse;">
<tr>
<td style="width:9.2%"><b>Load CSV file</b></td>
<td style="width:1%"><b>:</b></td>
<td style="width:15%"><input type="file" id="fileInputCSV" /></td>
</tr>
</table>
<table id="result"></table>
<script type="text/javascript">
// check browser support
// console.log(SimpleExcel.isSupportedBrowser);
var fileInputCSV = document.getElementById('fileInputCSV');
// when local file loaded
fileInputCSV.addEventListener('change', function (e) {
// parse as CSV
var file = e.target.files[0];
var csvParser = new SimpleExcel.Parser.CSV();
csvParser.setDelimiter(',');
csvParser.loadFile(file, function () {
// draw HTML table based on sheet data
var sheet = csvParser.getSheet();
var table = document.getElementById('result');
table.innerHTML = "";
sheet.forEach(function (el, i) {
var row = document.createElement('tr');
el.forEach(function (el, i) {
var cell = document.createElement('td');
cell.innerHTML = el.value;
row.appendChild(cell);
});
table.appendChild(row);
});
});
});
</script>
How do i supposed to do for add it into database?
The code you have is for load and parse the file in browser (client-side), if you want to insert the data of a XLSX file into a database like MySQL you need to upload the file to a server-side script (you said you are using PHP) and parse it using a library like PHPExcel.
You can use this PHPExcel Cheat Sheet to know how to parse the file.
If you need help creating the code to upload the file you can visit this link: PHP 5 File Upload.

How to initialize a function within an HTML file in a JavaScript file? (Chrome Apps)

I am working with a Scoring Board Chrome App. (I am new to Chrome Apps)
index.html - (just a part of the code) where user inputs the number of players for the scoring board, submits and opens another html file where a table and a number of rows are displayed based on the user input.
<form class="pure-form">
<fieldset>
<legend>Enter number of Players:</legend>
<input type="text" id="users" placeholder="Input Number">
<button type="submit" id="btn1" class="pure-button pure-button-primary">Submit</button>
</fieldset>
</form>
<script>
function(){
//localStorage.setItem('value', document.getElementById("users").value);
localStorage.value = document.getElementById("users").value;
}
</script>
<script type="text/javascript" src="js/main-sheet.js"></script>
<script type="text/javascript" src="js/alert.js"></script>
main-sheet.html - (also just a part of the code)
<table class="pure-table">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Score</th>
<th>Baluts</th>
</tr>
</thead>
<tbody>
<script type="text/javascript">
function addMoreRows(){
//var val = localStorage.getItem('value');
var val = localStorage.value;
document.getElementById("value").value = val;
for(var x=0; x<val; x++) {
var newRow = document.getElementById('pure-table').insertRow();
var newCell = newRow.insertCell();
newCell.innerHTML="<tr><td><input type='text' name='code'></td></tr>";
newCell = newRow.insertCell();
newCell.innerHTML="<tr><td><input type='text' name='name'></td></tr>";
newCell = newRow.insertCell();
newCell.innerHTML="<tr><td><input type='text' name='score'></td></tr>";
newCell = newRow.insertCell();
newCell.innerHTML="<tr><td><input type='text' name='baluts'></td></tr>";
}
}
</script>
The table head is displayed but rows aren't. Though I see why because function addMoreRows() hasn't really been called, and I don't know how.
And here is for the main-sheet.js
document.getElementById("btn1").addEventListener("click", function() {
if (!document.getElementById('users').value.trim()) {
//alert("Please enter the remarks");
chrome.app.window.create('../alert.html',{
'bounds': {
'width': 200,
'height': 200
},
'resizable': false,
});
}
else{
chrome.app.window.create('../main-sheet.html', {
'bounds': {
'width': 1000,
'height': 1000
},
'resizable': false,
});
}});
How do I call the function addMoreRows() to add Rows??
I would appreciate the help and corrections. Thank you.
Inline JavaScript will not be executed. This restriction bans both inline blocks and inline event handlers. You have to include a script file containing your javascript in your page
<script src="script.js" type="text/javascript"></script">
instead of using your javascript code (addMoreRows()) as inline JS within the page.
You will find more info on the Chrome Content-Security-Policy.
Hope it helps.
Looks like reading the documentation would really help, particularly Content Security Policy and Disabled Web Features. This means you cannot use localstorage and inline script.

tokbox-opentok passed to one side only

I am using tokbox trial for video chatting on my website. But the problem i am facing is that ::: User 1 can see and hear User 2 clearly. User 2 can see User 1 clearly, but user 2 couldnt here user 1. And code i am using
<html>
<head>
<title>Monkvyasa | Test</title>
<script src='http://static.opentok.com/webrtc/v2.2/js/opentok.min.js'></script>
<script type="text/javascript">
// Initialize API key, session, and token...
// Think of a session as a room, and a token as the key to get in to the room
// Sessions and tokens are generated on your server and passed down to the client
var apiKey = "xxxxxxx";
var API_KEY=apiKey;
var sessionId = "2_MX40NTAyMDgxMn5-xxxxxxxxxxxxxxxxxxxxHBXZEZoWHN-fg";
var token = "T1==cGFydG5lcl9pZD00NTAyMDgxMiZzaWc9ZDNiYjYyZGE2NTBkYmUzMTUyNGNjNDZjYzAzY2NjZWRhZGY3NTEyZjpyb2xlPW1vZGVyYXRvciZzZXNzaW9uX2lkPTJfTVg0xxxxxxxxxxxxxxxxxxxxxxxxBNM1JsYlRCUFdXWkhSSEJYWkVab1dITi1mZyZjcmVhdGVfdGltZT0xNDEzMjAwMjIxJm5vbmNlPTAuMTk1MzEwNTU0MzY1MjEwNSZleHBpcmVfdGltZT0xNDEzMjg0MzY5";
// Initialize session, set up event listeners, and connect
var session;
var connectionCount = 0;
function connect() {
session = TB.initSession(sessionId);
session.addEventListener("sessionConnected", sessionConnectHandler);
session.addEventListener('streamCreated', function(event){
e=event;
console.log(e);
for (var i = 0; i < event.streams.length; i++) {
streams = event.streams;
// Make sure we don't subscribe to ourself
alert("new user connected :)");
if (streams[i].connection.connectionId == session.connection.connectionId) {
return;
}
// Create the div to put the subscriber element in to
var div = document.createElement('div');
div.setAttribute('id', 'stream' + streams[i].streamId);
document.body.appendChild(div);
session.subscribe(streams[i], div.id);
}
});
session.connect(API_KEY, token);
}
function sessionConnectHandler(event) {
var div = document.createElement('div');
div.setAttribute('id', 'publisher');
var publisherContainer = document.getElementById('publisherContainer');
// This example assumes that a publisherContainer div exists
publisherContainer.appendChild(div);
var publisherProperties = {width: 500, height:450};
publisher = TB.initPublisher(API_KEY, 'publisher', publisherProperties);
session.publish(publisher);
}
function disconnect() {
session.disconnect();
}
connect();
</script>
</head>
<body>
<h1>Monkvysa videofeed test!</h1>
<input style="display:block" type="button" id="disconnectBtn" value="Disconnect" onClick="disconnect()">
<table>
<tr>
<td> <div id="publisherContainer"></div></td> <td><div id="myPublisherDiv"></div></td>
</tr>
</table>
</body>
</html>
Thanks in advance
The code looks mostly correct, except you're using an older form of the 'streamCreated' event handler. In the latest version of the API, you no longer need to iterate through the event.streams array, you actually get one invocation of the event handler per stream.
In order to further dig into the problem, would you be able to add a link to a gist containing all the console logs? To make sure the logs are being outputted, you can call OT.setLogLevel(OT.DEBUG); at the beginning of the script.
Lastly, the newer API is greatly simplified and you could save yourself the effort of DOM element creation and iteration. What you have implemented is basically identical to our Hello World sample applications, which you can find in any of our server SDKs, for example here: https://github.com/opentok/opentok-node/blob/61fb4db35334cd30248362e9b10c0bbf5476c802/sample/HelloWorld/public/js/helloworld.js

Passing a HTML element with ID

my question is about a code combining HTML5 features ContentEditable and localStorage.
Here is my two JS function, one for storing the user edit in the table cell, another for getting the value and pass it to the table cell.
<script type="text/javascript">
function storeUserEdit(id) {
var pre_value = document.getElementById(id).innerHTML;
localStorage.setItem("userEdit",pre_value);
}
function applyUserEdit() {
if (localStorage.getItem("userEdit")){
var new_value = localStorage.getItem("userEdit");
}
document.getElementById('prjSch_row1_col1').innerHTML = localStorage.getItem("userEdit");
}
</script>
and here these two functions embedded in body content:
...
<td id="prjSch_row1_col1" contenteditable="true" onkeyup="storeUserEdit(this.id)" >
</td>
<script>applyUserEdit()</script>
...
I want to use this to many table cells in my HTML page and how I can replace prjSch_row1_col1 with id and pass it to function getUserEdit();
thanks a lot!
Are you trying to do something like this. because what you mention in the question is not enough to me to think about an answer. When do you need to fire applyUserEdit() function, on page load or ...
Please let me know enough details.
16/08/2013 >
Very sorry for the delay! Please find the below code which I tested in Firefox. Is this the behavior you want. Please don't test in fiddler. It's not working there, I don't know why.
`
<head>
<script type="text/javascript">
function storeUserEdit(id) {
var pre_value = document.getElementById(id).innerHTML;
localStorage.setItem("userEdit",pre_value);
localStorage.setItem('userEditControl', id);
}
function applyUserEdit(id) {
var new_value = '';
if (localStorage.getItem("userEdit")){
new_value = localStorage.getItem("userEdit");
}
if(localStorage.getItem('userEditControl') === id){
document.getElementById(id).innerHTML = localStorage.getItem("userEdit");
}
//this is just to check whether the code is working
document.getElementById('log').value = document.getElementById('log').value + '\n' + localStorage.getItem("userEdit");
}
</script>
</head>
<body>
<table border="1">
<tr>
<td>User Name:</td>
<td id="uname" contenteditable="true" onkeyup="storeUserEdit(this.id)" onblur="applyUserEdit(this.id)">value...</td>
</tr>
<tr>
<td>Password:</td>
<td id="pword" contenteditable="true" onkeyup="storeUserEdit(this.id)" onblur="applyUserEdit(this.id)">value...</td>
</tr>
</table>
<textarea multiline="true" id="log"></textarea>
</body>
`
Please let me know if you have any issues...

Categories

Resources