Pass Object to Templated HTML - google-apps-script

I have an object I wold like to pass to a templated HTML file. If I use a simple variable, all is fine, as these work:
on the server side I have the following at the top of code.gs:
//Define this here globally so it is accessed in the HTML Template
var passedFestival = ' ';
var passedSID = ' ';
var passedRID = 'FALSE';
in the HTML file I have:
<script>
var passedFestival = '<?!= passedFestival ?>';
var passedSID = '<?!= passedSID ?>';
var passedRID = '<?!= passedRID ?>';
</script>
I can use these in later code and get the appropriate value. I want to also use an Object, which is the result of reading a couple rows from the spreadsheet, and basically results in the following outside any function, same as the other variables, above:
var testformOptions = [];
testformOptions['currencies'] = [{"currency":"CAD", "default":false, "defaultOption":"Interac", "paymentOptions":"Cheque|Credit Card|Interac|PayPal", "sheetrow":2}, {"currency":"USD", "default":true, "defaultOption":"PopMoney", "paymentOptions":"Cheque|Credit Card|PayPal|PopMoney", "sheetrow":3}];
testformOptions['meals'] = {"use":true, "required":false, "default":"Omnivore", "values":"Omnivore|Vegan"};
in the HTML file I can reference the object's individual values:
if ('<?!= testformOptions.currencyOptions.use ?>') {
$("#currencies").show();
}
But I would rather copy the object over completely and reference it as part of the client side data. I have tried a few things, most of which I understand why they didn't work, but I thought this would:
var formOptions = jQuery.extend(true, {}, <?!= testformOptions?>;
I have tried saving the data to a variable as json, but that didn't work since I have single quotes and other special characters in my final object.
Is there any way to get an object passed into an object on the client side outside using google.script.run to pass it after loading? I am reading the spreadsheet data as part of the initial doGet so I figured it may be faster to use templated HTML and pass the object.
EDIT
Thanks to the reply, I have working code. The final sample reads as follows. Some items are left out to allow focusing on the important parts.
Code.gs:
var passedSID = ' ';
var passedRID = 'FALSE';
function doGet(passed) {
if(passed.parameter.rid && passed.parameter.msid){
// A registration ID and Spreadsheet ID were passed so this is to edit an existing registration
passedSID = passed.parameter.msid;
passedRID = passed.parameter.rid;
var registrationValues = getRegistrationValues(passedSID, passedRID);
}
else if(passed.parameter.msid){
// A Spreadsheet ID was passed so this is to complete a new registration
passedSID = passed.parameter.msid;
}
//get the form options from the appropriate spreadsheet file
//getFormOptions() is from Tutorial: Simple Mail Merge
//https://developers.google.com/apps-script/articles/mail_merge
testformOptions = getFormOptions(passedSID);
//Create the HTML template
var template = HtmlService.createTemplateFromFile('Index');
template.data = JSON.stringify(testformOptions);
// Build and return HTML in IFRAME sandbox mode.
return template.evaluate()
.setTitle('Registration Form').setWidth(620).setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
function include(filename) {
return HtmlService.createTemplateFromFile(filename).evaluate()
.getContent();
}
Index.html:
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
<link href="https://fonts.googleapis.com/css?family=Raleway:100" rel="stylesheet">
<html>
<body>
<div id="mybody">
<form>
<!-- Boring form html -->
</form>
</div>
</body>
</html>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
var formOptions = $.extend(true, {}, <?!= data ?>);
</script>
<!-- Use a templated HTML printing scriptlet to import JavaScript. -->
<?!= HtmlService.createHtmlOutputFromFile('jquery_cloneform_js').getContent(); ?>
<?!= include('JavaScript'); ?>
And in JavaScript.html:
<script>
var passedSID = '<?!= passedSID ?>';
var passedRID = '<?!= passedRID ?>';
// use onload to call initialization after the document loads
window.onload = setForm;
function setForm(){
var optionArray = [];
var defaultOption = '';
if (formOptions.currencyOptions.use) {
$("#currencies").show();
//Set the options for the currency
var options = formOptions.currencyOptions.values;
defaultOption = formOptions.currencyOptions.defaultOption;
optionArray = options.split("|");
setSelectOptions('regcurrency', optionArray, defaultOption);
var options = formOptions.currencies[1].paymentOptions;
defaultOption = formOptions.currencies[1].defaultOption;
optionArray = options.split("|");
setSelectOptions('paymentMethod', optionArray, defaultOption);
}
}

How about a following answer?
Modification points :
var testformOptions = [];
testformOptions['currencies'] = [{"currency":"CAD", "default":false, "defaultOption":"Interac", "paymentOptions":"Cheque|Credit Card|Interac|PayPal", "sheetrow":2}, {"currency":"USD", "default":true, "defaultOption":"PopMoney", "paymentOptions":"Cheque|Credit Card|PayPal|PopMoney", "sheetrow":3}];
testformOptions['meals'] = {"use":true, "required":false, "default":"Omnivore", "values":"Omnivore|Vegan"};
About the above script, testformOptions is defined as an array. So testformOptions['currencies'] and testformOptions['meals'] cannot be imported. So please modify from var testformOptions = []; to var testformOptions = {};.
When it passes the object, please use JSON.stringify().
The scripts reflected above modifications are as follows.
code.gs :
function doGet() {
var testformOptions = {};
testformOptions['currencies'] = [{"currency":"CAD", "default":false, "defaultOption":"Interac", "paymentOptions":"Cheque|Credit Card|Interac|PayPal", "sheetrow":2}, {"currency":"USD", "default":true, "defaultOption":"PopMoney", "paymentOptions":"Cheque|Credit Card|PayPal|PopMoney", "sheetrow":3}];
testformOptions['meals'] = {"use":true, "required":false, "default":"Omnivore", "values":"Omnivore|Vegan"};
var t = HtmlService.createTemplateFromFile('index');
t.data = JSON.stringify(testformOptions);
return t.evaluate();
}
index.html
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<p id="disp"></p>
<script>
var data = $.extend(true, {}, <?!= data ?>);
$('#disp').text(JSON.stringify(data));
</script>
Result :
{
"currencies": [
{
"currency": "CAD",
"default": false,
"defaultOption": "Interac",
"paymentOptions": "Cheque|Credit Card|Interac|PayPal",
"sheetrow": 2
},
{
"currency": "USD",
"default": true,
"defaultOption": "PopMoney",
"paymentOptions": "Cheque|Credit Card|PayPal|PopMoney",
"sheetrow": 3
}
],
"meals": {
"use": true,
"required": false,
"default": "Omnivore",
"values": "Omnivore|Vegan"
}
}
If I misunderstand your question, I'm sorry.

Related

getting spreadsheet data to chart data array

Although I found similar posts elsewhere, I still cannot solve my issue.
I want to load locations on a html sidebar page on google spreadsheet, but the only example I find are hard-coded locations.
Here is an example, on HTML page (I removed API Key): this one works for me.
<body>
<div class="container">
<div id="map_div" style="width: 500px; height: 500px"></div>
</div> <!-- CLOSE CONTAINER -->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {
"packages":["map"],
"mapsApiKey": "xxxx"
});
google.charts.setOnLoadCallback(drawChart);
function drawChart(arrayToData) {
var data = new google.visualization.arrayToDataTable(
[["Lat", "Long","Nom"],
[45.7660889, 4.794056299999999, "Person1"],
[45.8167227, 4.8341048, "Person2"],
[45.7796433, 4.8037871, "Person3"],
[45.7780849, 4.921768399999999, "Person4"]]
);
var map = new google.visualization.Map(document.getElementById('map_div'));
map.draw(data, {
showTooltip: true,
showInfoWindow: true
});
}//function drawChart() {
</script>
</body>
And I would like to have something looking like that, where data locations are not hard-coded but comes from spreadsheet data :
google.charts.setOnLoadCallback(drawChart);
var ss = SpreadsheetApp.openByUrl("xxxx");
var datatable = ss.getRange("listNamesAdresses");
function drawChart(arrayToData) {
var dataToArray=document.getElementById("listNamesAdresses");
var data = new google.visualization.arrayToDataTable(
dataToArray
);
var map = new google.visualization.Map(document.getElementById('map_div'));
map.draw(data, {
showTooltip: true,
showInfoWindow: true
});
}//function drawChart() {
I'm aware this is not correct, but I tried many combinations, still cannot solve it. Your help is welcome !
Here is a sharable example of what I made :
Link to a copy of my Map Test
I adapted it from my spreadsheet but went out of my quota for my API key, so I could'nt test it yet. I hope this will be fine !
Many thanks in advance
EDIT 2 :
I followed ziganotschka's suggestions (thank you very much for your time) : I couldn't apply the HtmlCreateOutputFromFil("index.html") so I stuck to my code for displaying a sidepage Html. For the rest of it : I now have a map (first victory!).
But, it says : "no data points to show".
I checked on values return by getAddresses function, seems OK. For getting easier on it, I changed the function to an easier one : getGeoCodesAndNames. This one returns, as it says, geocode latitude, longitude, and name.
Here are my new code sample and link to the new version of the spreadsheet :
Gs-code :
function getGeoCodesAndNames(){
//get addresses and names list
var namesAddresses=ss.getRange("ListNamesAddresses");
var a_values=namesAddresses.getValues();
Logger.log(a_values);
/* returns
[[Lat, Lon, Name],
[45.7660889, 4.79405629999999, person1],
[45.8167227, 4.8341048, person2],
[45.7796433, 4.8037871, person3],
[45.7780849, 4.921768399999999, person4]]
*/
return a_values;
}//function getGeoCodesAndNames(){
function testMap2(){
var template = HtmlService.createTemplateFromFile("carte2");
var html = template.evaluate();
html.setTitle("Display Map 2").setHeight(550).setWidth(550);
SpreadsheetApp.getUi().showModalDialog(html, "Locations")
}//function testCarte1(){
and HTML code :
<script type="text/javascript">
window.onload = google.script.run.withSuccessHandler(onSuccess).getGeoCodesAndNames();
function onSuccess (arrayToData){
google.charts.load("current", {
"packages":["map"],
"mapsApiKey": "AIzaSyC4WPcWGMZRoqSAfZ0F4RzvWtN6Jy7hmdE"
});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable(arrayToData);
var map = new google.visualization.Map(document.getElementById('map_div'));
map.draw(data, {
showTooltip: true,
showInfoWindow: true
});
}// function drawChart() {
}//function onSuccess (arrayToData){
</script>
And here is the link to the new spreadsheet version :
TestMap2
Do I need to publish it as a web app if I just want to have a side page ? On previous projects I had, I could add datas from a side-page to a spreadsheet without it. In the oppposite ways, can you confirm I need to do it ? I tried, did not change anything on my current result : maybe I made something wrong.
Many thanks again for your help !
EDIT 3 :
I finally got it : My geocode/address function were not returning a proper format for coordinates, because of two things :
1) I'm using French typing, ie dot are replaced with commas in numbers
2) I had to add one more """ symbol at beginning and ending of each string part in the array.
Here is the correct function (might be improved, but..does the job):
function getGeoCodesAndNames(){
//get addresses and names list
var namesAddresses=ss.getRange("ListNamesAddresses");
var a_values=namesAddresses.getValues();
for (var i=0;i<a_values.length;i++){
for (var j=0;j<a_values[0].length;j++){
var value=a_values[i][j];
if (typeof value == "string"){
a_values[i][j]="\"" + value + "\"";
}
}
}
return a_values;
}//function getGeoCodesAndNames(){
Many thanks to the people who helped me !
To combine using the Visualization API in Javascript with retrieving spreadsheet data with Apps Script - you need to use a WebApp
Use google.script.run to pass data from the serverside to clientside
Sample:
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile("index.html");
}
function getDatafromSheet(){
var ss = SpreadsheetApp.openByUrl("xxxx");
// getNamedRanges()[0] works if you have only one named range
var datatable = ss.getNamedRanges()[0].getRange().getValues();
return datatable;
}
index.html
<body>
<div class="container">
<div id="map_div" style="width: 500px; height: 500px"></div>
</div> <!-- CLOSE CONTAINER -->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
window.onload = google.script.run.withSuccessHandler(onSuccess).getDatafromSheet();
function onSuccess (arrayToData){
google.charts.load("current", {
"packages":["map"],
"mapsApiKey": "AIzaSyDCKzjezYeUDd2ugtFnzokCIpV1YpLmmEc"
});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.arrayToDataTable(arrayToData);
var map = new google.visualization.Map(document.getElementById('map_div'));
map.draw(data, {
showTooltip: true,
showInfoWindow: true
});
}
}
</script>
</body>

Populating html sidebar with js variable data

I'm a fast learning beginner with Google Sheets Script. In the apps I've done so far the sidebars I've made have included buttons and text, but nothing passed from variables. I'll note that I understand Javascript reasonably well, but haven't branched into jquery as yet, though I have a good book on the topic.
In this case I have variable values taken from two different spreadsheets that I'd like passed to the sidebar so that the user can view data and set an appointment.
My .gs code:(This is server side code)
function apptSidebar2() {
var html = HtmlService.createHtmlOutputFromFile('setApptsPage2')
.setTitle('Counselor Connect Easy!')
.setWidth(300);
SpreadsheetApp.getUi().showSidebar(html);
}
function setAppts2() {
//get all the data for client appointment
var setupSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Setup');
var shID=setupSheet.getRange(1,2).getValue();
var feedSheet = SpreadsheetApp.openById(shID);
var dataSheet = feedSheet.getSheetByName('StudentData');
var lastColumn = dataSheet.getLastColumn();
var lastRow = dataSheet.getLastRow();
for(var i=lastRow;i>0;i--) {
if(dataSheet.getRange(i,1).getValue()==thisID) {
var clientData = dataSheet.getRange(i,1,1,lastColumn).getValues();
}
}
var SID = thisID;
var SLN = clientData[0][1];
var SFN = clientData[0][2];
var b1r = clientData[0][3].toString();
var b1t = clientData[0][4].toString();
var b1c = clientData[0][5].toString();
var SB1 = b1r+" "+b1t+" "+b1c;
var b2r = clientData[0][6].toString();
var b2t = clientData[0][7].toString();
var b2c = clientData[0][8].toString();
var SB2 = b2r+" "+b2t+" "+b2c;
var b3r = clientData[0][9].toString();
var b3t = clientData[0][10].toString();
var b3c = clientData[0][11].toString();
var SB3 = b3r+" "+b3t+" "+b3c;
var b4r = clientData[0][12].toString();
var b4t = clientData[0][13].toString();
var b4c = clientData[0][14].toString();
var SB4 = b4r+" "+b4t+" "+b4c;
var b5r = clientData[0][15].toString();
var b5t = clientData[0][16].toString();
var b5c = clientData[0][17].toString();
var SB5 = b5r+" "+b5t+" "+b5c;
var b6r = clientData[0][18].toString();
var b6t = clientData[0][19].toString();
var b6c = clientData[0][20].toString();
var SB6 = b6r+" "+b6t+" "+b6c;
apptSidebar2();
}
And my html for the sidebar, which I suspect is grossly uninformed in terms of how I need to connect the two. For all I know I'm closer than I think:
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<head>
<base target="_top">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/timepicker/1.3.5/jquery.timepicker.min.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$( function() {
$( "#datepicker" ).datepicker();
} );
</script>
<script type="text/javascript">
function getStudent() {
if(!document.getElementById) return;
var apptDiv2 = document.getElementById("appt2");
}
</script>
</head>
<body>
<div id="container" style="padding: 10px; text-align:center;">
<div id="appt2">
<b>Student Data</b>
<p id="name">Student Name</p>
<p id = "id">nnnnn</p>
<p id = "reason">Why</p>
<p id = "notes">More why</p>
<p id = "blk1">Block 1</p>
<p id = "blk2">Block 2</p>
<p id = "blk3">Block 3</p>
<p id = "blk4">Block 4</p>
<p id = "blk5">Block 5</p>
<p id = "blk6">Block 6</p>
<input type="text" id="datepicker" value="click to choose date">
</div>
</div>
<div style=
"width: 100%;
position: fixed;
bottom: 0;
width: 100%;
text-align:center;
background-color:black;
text-color:white;">
<p><b>©FastAdmin Solutions</b></p>
</div>
</div>
</body>
</html>
Not meant to be a comprehensive answer:
You could change this:
<script>
$( function() {
$( "#datepicker" ).datepicker();
} );
</script>
To something like this
HTML(clientside):
<script>
$( function() {
$( "#datepicker" ).datepicker();
google.script.run
.withSuccessHandler('insertHtmlIntoADiv')
.getDesiredDataInHtmlFormat();
} );
function insertHtmlIntoADiv(hl){
$('#mydiv').html(hl);
}
</script>
CODE(ServerSide):
getDesiredDataInHtmlFormat(){
//generate html integrated with wanted data and store it in a string and return it. It will be picked up by the success handler.
}
For more info on google.script.run look here.
To directly set variables in the as-constructed sidebar, you'll need to create an HtmlTemplate from the sidebar's HTML file, pass that to the setAppts function, set those values on the template object, and then return the "filled" template to the calling function, to be built into an HtmlOutput and displayed:
function getApptSidebarOutput() {
var template = HtmlService.createTemplateFromFile("a filename");
fillAppts_(template);
return template.evaluate();
}
function fillAppts_(theTemplate) {
theTemplate.someVarName = some value;
theTemplate.otherVar = some other value;
...
return theTemplate;
}
In your HTML file, these variables can be used directly as someVarName and otherVar.
Recommended reading:
template guide
Adding variables to templates
Note that depending on what this data is and who is using it, you may be better off with a fully async design, where the sidebar is constructed without this data, and queries for up-to-date info periodically (like right before submitting an appointment request, or otherwise every 5-10 minutes). The idea being, schedule availabilities change, but the sidebar can be left open.

google.script.run is returning undefined. How do I fix it?

I'm trying to get an array from a spreadsheet and use it to populate a dropdown. Here is my code
code.gs
function doGet() {
var page = HtmlService.createTemplateFromFile('Index');
return page.evaluate()
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function getArrayList(){
var ss = SpreadsheetApp.openById("1EjRFAYiMBw5BuNhFJRUVG4MpUjIIy8Oey5JLyiYxj3c");
var sheet = ss.getSheetByName("Nomes");
var values = sheet.getDataRange().getValues();
var array = [];
for each (var item in values){
array.push(item[0]);
}
return array
}
Index.html
<!DOCTYPE html>
<html>
<?!= include('jQuery'); ?>
<div class="demo" >
<form id="myForm">
<select id="selectNumber">
<option>Choose a number</option>
</select>
</form>
<?!= include('JavaScript'); ?>
</div>
</html>
JavaScript.html
<script>
var options = google.script.run.getArrayList();
console.log(options);
$('#selectNumber').empty();
$.each(options, function(i, p) {
$('#selectNumber').append($('<option></option>').val(p).html(p));
});
</script>
jQuery.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script>
If instead of using var options = google.script.run.getArrayList(); on the JavaScript.html file, I pass a literal array var options = ["1","2","3"]; my code works like a charm.
I know that the problem is that google.script.run is returning Undefined, but I don´t know what I´m doing wrong. Can someone please help me?
Is this useful for you?
google.script.run.function() doesn't return values. So options of var options = google.script.run.getArrayList(); is Undefined. Use withSuccessHandler() to get the returned values from getArrayList(). Below is the updated JavaScript.html.
<script>
google.script.run.withSuccessHandler(sample).getArrayList();
function sample(options) {
$('#selectNumber').empty();
$.each(options, function(i, p) {
$('#selectNumber').append($('<option></option>').val(p).html(p));
});
}
</script>
values is an array of arrays. To get all of the data you need to do something like:
var a=[];
for(var i=0;i<values.length;i++)
{
for(var j=0;j<values[0].length;j++)
{
a.push(values[i][j]);
}
}
or just return values

How to pass a parameter to html?

I have a script that uses the file picker but I need to pass a specific parameter which is called userId and is kept as a global variable in the calling script. As the calls are asynchronous it seems I cannot access this parameter. Is there a way to access the parameter from the html file or pass this parameter to the html?
I might be mixing templated html and non templated.
Here is the calling code (initiated through a menu item in a spreadsheet):
function syncStudentsFile(userId, ss) {
scriptUser_(userId); // save userId
Logger.log('SRSConnect : syncStudentsFile : userId:'+userId); // userId is correct here
var ss = SpreadsheetApp.getActiveSpreadsheet();
var html = HtmlService.createHtmlOutputFromFile('PickerSync.html')
.setWidth(600).setHeight(425);
SpreadsheetApp.getUi().showModalDialog(html, 'Select a file');
}
function scriptUser_(userId) {
if (userId !== undefined)
sUserId = userId; // Global variable
try { return sUserId; } catch (e) { return undefined; }
}
function getOAuthToken() { // used by Picker
DriveApp.getRootFolder();
return ScriptApp.getOAuthToken();
}
Here is the html picker file:
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script type="text/javascript">
var DEVELOPER_KEY = '..............';
var DIALOG_DIMENSIONS = {width: 600, height: 425};
var pickerApiLoaded = false;
/**
* Loads the Google Picker API.
*/
gapi.load('picker', {'callback': function() {
pickerApiLoaded = true;
}});
/**
* Gets the user's access token from the server-side script so that
* it can be passed to Picker. This technique keeps Picker from needing to
* show its own authorization dialog, but is only possible if the OAuth scope
* that Picker needs is available in Apps Script. Otherwise, your Picker code
* will need to declare its own OAuth scopes.
*/
function getOAuthToken() {
google.script.run.withSuccessHandler(createPicker)
.withFailureHandler(showError).getOAuthToken();
}
/**
* Creates a Picker that can access the user's spreadsheets. This function
* uses advanced options to hide the Picker's left navigation panel and
* default title bar.
*
* #param {string} token An OAuth 2.0 access token that lets Picker access the
* file type specified in the addView call.
*/
function createPicker(token) {
if (pickerApiLoaded && token) {
var uploadView = new google.picker.DocsUploadView();
var picker = new google.picker.PickerBuilder()
// Instruct Picker to display only spreadsheets in Drive. For other
// views, see https://developers.google.com/picker/docs/#otherviews
.addView(google.picker.ViewId.DOCS)
.addView(google.picker.ViewId.RECENTLY_PICKED)
.addView(uploadView)
.hideTitleBar()
.setOAuthToken(token)
.setDeveloperKey(DEVELOPER_KEY)
.setCallback(pickerCallback)
// Instruct Picker to fill the dialog, minus 2 pixels for the border.
.setSize(DIALOG_DIMENSIONS.width - 2,
DIALOG_DIMENSIONS.height - 2)
.build();
picker.setVisible(true);
} else {
showError('Unable to load the file picker.');
}
}
/**
* A callback function that extracts the chosen document's metadata from the
* response object. For details on the response object, see
* https://developers.google.com/picker/docs/result
*
* #param {object} data The response object.
*/
function pickerCallback(data) {
var action = data[google.picker.Response.ACTION];
if (action == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
var id = doc[google.picker.Document.ID];
google.script.host.close();
// --------------> user global parameter sUserId set earlier
google.script.run.PickerSyncFile(sUserId, id);
} else if (action == google.picker.Action.CANCEL) {
google.script.host.close();
}
}
/**
* Displays an error message within the #result element.
*
* #param {string} message The error message to display.
*/
function showError(message) {
document.getElementById('result').innerHTML = 'Error: ' + message;
}
</script>
<div>
<script>getOAuthToken()</script>
<p id='result'></p>
<input type="button" value="Close" onclick="google.script.host.close()" />
</div>
Here is the picker code:
function pickerSyncFile(userId, id) {
Logger.log('userId:'+userId); // BUG: it is null
Logger.log('id:'+id); // id returned well from picker
// rest of code here but userId was is incorrect
}
The safest way is to pass the needed data to the HTML directly. If you use properties or cache service it can get complex or fail under multiple simultaneous users.
There are many techniques to pass an initial object from the server (.gs) to the client (.html).
Using HtmlTemplate, you may do:
//.gs file
function doGet() {
var htmlTemplate = HtmlService.createTemplateFromFile('template-client');
htmlTemplate.dataFromServerTemplate = { first: "hello", last: "world" };
var htmlOutput = htmlTemplate.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('sample');
return htmlOutput;
}
and in your template-client.html file:
<!DOCTYPE html>
<script>
var data = <?!= JSON.stringify(dataFromServerTemplate) ?>; //Stores the data directly in the javascript code
// sample usage
function initialize() {
document.getElementById("myTitle").innerText = data.first + " - " + data.last;
//or use jquery: $("#myTitle").text(data.first + " - " + data.last);
}
// use onload or use jquery to call your initialization after the document loads
window.onload = initialize;
</script>
<html>
<body>
<H2 id="myTitle"></H2>
</body>
</html>
It is also possible to do it without using templating, by appending a hidden div to an HtmlOutput:
//.gs file:
function appendDataToHtmlOutput(data, htmlOutput, idData) {
if (!idData)
idData = "mydata_htmlservice";
// data is encoded after stringifying to guarantee a safe string that will never conflict with the html.
// downside: increases the storage size by about 30%. If that is a concern (when passing huge objects) you may use base94
// or even base128 encoding but that requires more code and can have issues, see http://stackoverflow.com/questions/6008047/why-dont-people-use-base128
var strAppend = "<div id='" + idData + "' style='display:none;'>" + Utilities.base64Encode(JSON.stringify(data)) + "</div>";
return htmlOutput.append(strAppend);
}
// sample usage:
function doGet() {
var htmlOutput = HtmlService.createHtmlOutputFromFile('html-sample')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('sample');
// data can be any (serializable) javascript object.
// if your data is a native value (like a single number) pass an object like {num:myNumber}
var data = { first: "hello", last: "world" };
// appendDataToHtmlOutput modifies the html and returns the same htmlOutput object
return appendDataToHtmlOutput(data, htmlOutput);
}
and in your output-client.html:
<!DOCTYPE html>
<script>
/**
* getDataFromHtml
*
* Inputs
* idData: optional. id for the data element. defaults to "mydata_htmlservice"
*
* Returns
* The stored data object
*/
function getDataFromHtml(idData) {
if (!idData)
idData = "mydata_htmlservice";
var dataEncoded = document.getElementById(idData).innerHTML;
var data = JSON.parse(atob(dataEncoded));
return data;
}
// sample usage of getDataFromHtml
function initialize() {
var data = getDataFromHtml();
document.getElementById("myTitle").innerText = data.first + " - " + data.last;
//or use jquery: $("#myTitle").text(data.first + " - " + data.last);
}
// use onload or use jquery to call your initialization after the document loads
window.onload = initialize;
</script>
<html>
<body>
<H2 id="myTitle"></H2>
</body>
</html>
Both methods are compared and better explained in this little github I made:
https://github.com/zmandel/htmlService-get-set-data
I often use HtmlService templates to push static values to the client.
index.html
<script>
var domain = "<?=domain?>";
</script>
code.gs
var ui = HtmlService.createTemplateFromFile('Sidebar');
ui.domain = domain;
return ui.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle(strings[lang][domain]);
In your code:
function scriptUser_(userId) {
if (userId !== undefined)
sUserId = userId; // Global variable
try { return sUserId; } catch (e) { return undefined; }
}
You are assigning a value to the global variable named sUserId. But, then when you try to retrieve it, nothing is there. Global variables loose their value as soon as the current instance of the code bring run is completed. Global variable don't persist their values.
You'll need to use the Properties Service to store the value. Or you could use the Cache service. If you want the value of the user id to expire after some time, use cache service.
By Appending to the HTML File, as shown below.
within Code.gs
function showDialog() {
var html = HtmlService.createHtmlOutputFromFile('html-sample')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(600)
.setHeight(425);
var data = "Hello World!";
var strAppend = "<div id='id_for_div' style='display:none;'>" + data + "</div>";
html.append(strAppend);
var title = "Demo";
SpreadsheetApp.getUi().showModalDialog(html, title); // or DocumentApp or SlidesApp or FormApp.
}
html-sample.html
<!DOCTYPE html>
<html>
<head>
<script>
function setText(text) {
var element = document.getElementById("myid");
element.innerHTML = text;
}
function getDataFromHtml() {
var id = "id_for_div";
var dataEncoded = document.getElementById(id).innerHTML;
setText(dataEncoded);
}
</script>
</head>
<body>
<h1 id="myid">Sample Text</h1>
<button onclick="getDataFromHtml()">Try Now!</button>
</body>
</html>
Click the 'Try Now!' Button and See the Magic!
This post provides the solution how to pass parameter to a templated html:
html = HtmlService.createTemplateFromFile('page2');
html.id = s1;
Then in page 2 use the the tag to print out the id value;
<div class="info" >
<span id="ID" name="ID"><?=id?></span>
</div>

How can I read the POST data in AS3?

I am creating the below url request which launches a flex application through the mentioned url. I have also added data and set url req method to POST. How can I read this POST data in my Flex Application which is being launched
var urlReq:URLRequest = new URLRequest();
var requestVars:URLVariables = new URLVariables();
requestVars.id = 'abc';
urlReq.data = requestVars;
urlReq.method = URLRequestMethod.POST;
urlReq.url = '../../bin-debug/FlexApp.html';
navigateToURL(urlReq);
Could you pass your variables within the url and then use flashvars via swfobject to pass them to the target app?
I've had more or less similar issue, and used this method.
In my first swf:
var urlReq:URLRequest = new URLRequest(String("game.html?user_id="+userId+"&user_code="+userCode));
And then in game.html I parsed those variables and sent then as flashvars:
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi,
function(m,key,value) {
vars[key] = value;
});
return vars;
};
var flashvars = {
user_id: getUrlVars()["user_id"],
user_code: getUrlVars()["user_code"]
};
var params = {
quality: "high",
bgcolor: "#000000",
play: "true",
loop: "true",
wmode: "window",
scale: "showall",
menu: "true",
devicefont: "false",
allowScriptAccess: "true"
};
swfobject.embedSWF("preloader.swf", "flashContent", "980", "663", "11.2.0",false, flashvars, params);
</script>
And finally in my target swf I received them like this:
var userId:String = loaderInfo.parameters.user_id as String;
var userCode:String = loaderInfo.parameters.user_code as String;
I hope this helps, and if not, then I probably didn't understand the main issue.
The POST data is sent to the server, so if you want to read it on FlexApp.html from the client then the server needs to echo it back on that page somehow. Otherwise you could use a GET request and access the request parameters using JavaScript window.location.search.
Here's an example using PHP to output the POST variables as JSON to the page:
<script>
var post_params = <? echo json_encode($_POST); ?>
function getPostParam(name){
return post_params[name];
}
</script>
Call from JavaScript:
alert(getPostParam("id"));
Call from ActionScript:
trace(ExternalInterface.call("getPostParam", "id"));