Thanks for playing!
Type your answer here and it will print on a reciept in the gallary!
(input-box:2bind _var1,"=XX=",1,"Name")
(input-box:2bind _var2,"=XX=",1,"Answer")
<script src=”https://code.jquery.com/jquery-3.3.1.min.js”></script>
<script>
var sendData = JSON.stringify({
"var1": harlowe.State.variables['name'],
"var2": harlowe.State.variables['answer']
});
$.ajax({
url:"https://script.google.com/macros/s/AKfycbysbEmHp0IwxdcmuBMJ74VIsrzpWl3vsr32N_CXUw/exec",
method:"POST",
dataType: "json",
data: sendData
}).done(function() {});
</script>
And here is the code in my google sheet.
// 1. Enter sheet name where data is to be written below
var SHEET_NAME = "DATA";
// 2. Run > setup
//
// 3. Publish > Deploy as web app
// - enter Project Version name and click 'Save New Version'
// - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously)
//
// 4. Copy the 'Current web app URL' and post this in your form/script action
//
// 5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
// If you don't want to expose either GET or POST methods you can comment out the appropriate function
function doGet(e){
return handleResponse(e);
}
function doPost(e){
return handleResponse(e);
}
function handleResponse(e) {
// shortly after my original solution Google announced the LockService[1]
// this prevents concurrent access overwritting data
// [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
// we want a public lock, one that locks for all invocations
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
try {
// next set where we write the data - you could write to multiple/alternate destinations
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var sheet = doc.getSheetByName(SHEET_NAME);
// we'll assume header is in row 1 but you can override with header_row in GET/POST data
//var headRow = e.parameter.header_row || 1; Hawksey's code parsed parameter data
var postData = e.postData.contents; //my code uses postData instead
var data = JSON.parse(postData); //parse the postData from JSON
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow()+1; // get next row
var row = [];
// loop through the header columns
for (i in headers){
if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column
row.push(new Date());
} else { // else use header name to get data
row.push(data[headers[i]]);
}
}
// more efficient to set values as [][] array than individually
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// return json success results
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e){
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty("key", doc.getId());
}
I know its a stupid error and you probably get the exact same question all the time but my fly brain cant figure it out.
The Google Sheets API has changed at least once since that original Twine & Sheets article was written, and searching with Google shows there are a number of others having issues with getting older code to work correctly.
There are a number of potential issues with your Passage content:
1: You are storing the input values in two Temporary variables named _var1 & _var2, but you are storing the current values of two Story Variables named name & answer to the properties of the sendData object.
2: You are executing contents of the <script> element during the Passage content processing step, however the Reader doesn’t get to interact with the two input fields until after the Passage content processing step has finished and the generated HTML elements have been added to the web-page.
eg. you are sending the current value of the two named Story Variables to the Google Sheet before the Reader can enter values into the input fields.
To allow the Reader time to interact with the input fields before you seen the entered values to the Google Sheet you need to delay the execution of the <script> element. One method you can use to do that is to place that element within an interactive element like a link.
warning: the following code has not been tested, because I don’t have a Google Sheet setup to receive data from a Twine project.
Thanks for playing!
Type your answer here and it will print on a reciept in the gallary!
(input-box: 2bind $name, "=XX=", 1, "Name")
(input-box: 2bind $answer, "=XX=", 1, "Answer")
(link-repeat: "Send Date")[
(if: $name is not "" and $answer is not "")[
<script>
var sendData = JSON.stringify({
"var1": harlowe.State.variables['name'],
"var2": harlowe.State.variables['answer']
});
$.ajax({
url:"https://script.google.com/macros/s/AKfycbysbEmHp0IwxdcmuBMJ74VIsrzpWl3vsr32N_CXUw/exec",
method:"POST",
dataType: "json",
data: sendData
}).done(function() {});
</script>
]
]
<script src=”https://code.jquery.com/jquery-3.3.1.min.js”></script>
here is a link to a copy of the doc: Copy of Copy of Dark Lens Database - Google Sheets
And here is the output from your current code:
|Timestamp|name|answer|
|1/21/2021|undefined|undefined|
|1/21/2021|undefined|undefined|
|1/21/2021|undefined|undefined|
|1/21/2021|undefined|undefined|
|1/21/2021|undefined|undefined|
|1/23/2021|undefined|undefined|
|1/23/2021|undefined|undefined|
|1/23/2021|undefined|undefined|
I know that editing the receiving code will be a trek so i am prepared to pay you 20 bucks (USD) for your effort once it works.
You have named the columns in your spread sheet name & answer, but you have named the properties of your sendData object var1 & var2 …
var sendData = JSON.stringify({
"var1": harlowe.State.variables['name'],
"var2": harlowe.State.variables['answer']
});
…and it is this difference in column & property naming that is the likely cause of the issue.
The following variation of your original Passage content has been changed so the properties of the sendData object are now named the same as the spreadsheet’s name & answer columns.
Thanks for playing!
Type your answer here and it will print on a reciept in the gallary!
(input-box: 2bind $name, "=XX=", 1, "Name")
(input-box: 2bind $answer, "=XX=", 1, "Answer")
(link-repeat: "Send Date")[
(if: $name is not "" and $answer is not "")[
<script>
var sendData = JSON.stringify({
"name" : harlowe.State.variables['name'],
"answer" : harlowe.State.variables['answer']
});
$.ajax({
url: "https://script.google.com/macros/s/AKfycbysbEmHp0IwxdcmuBMJ74VIsrzpWl3vsr32N_CXUw/exec",
method:"POST",
dataType: "json",
data: sendData
}).done(function() {});
</script>
]
]
<script src=”https://code.jquery.com/jquery-3.3.1.min.js”></script>