Skip to content

Instantly share code, notes, and snippets.

@brizzio
Last active February 20, 2018 20:53
Show Gist options
  • Save brizzio/c1b780dfc09efab4d4e6591761f4c11c to your computer and use it in GitHub Desktop.
Save brizzio/c1b780dfc09efab4d4e6591761f4c11c to your computer and use it in GitHub Desktop.
connect a web form to a specific gsheet

The script above will configure your Google Sheet to handle a GET request (function doGet()), tells the spreadsheet where to place the received data (lines 21–38), and sets the allowed MIME type (setMimeType(ContentService.MimeType.JSON)). Give it a read—Will Patera did a great job explaining the script with his comments so I left them in there. (The original gist can be found here.)

Save the script and give it an appropriate name. Then go to the “Run” menu and select “setup.”

You might be asked to give Google Scripts to use your Google account.

Once you’ve given your authorization, go to the “Publish” menu and select “Deploy as web app.”

You will then be presented with a few options with which to customize your script.

The last two of these three options are extremely important to set correctly or you won’t be able to access your script with an AJAX request. You must execute the app as yourself and you must give “Anyone, even anonymous” access to the app. Without these settings your script will reject any request from a different server, like your form’s AJAX request, because it won’t be configured to allow for cross-origin resource sharing (CORS).

Once you’ve configured these options, go ahead and click “Deploy.”

You will the be presented with the URL for your web app. This is where we’ll be sending our AJAX request so copy that URL and save it for later.

Finally, we’ll connect our HTML form with our Google Script with a little JavaScript/jQuery. Nothing too crazy here, either. We’re preventing the form from submitting normally and instead constructing an AJAX request to the URL for our web app/script that we obtained earlier.

The only interesting part is the data that we’re sending. Our script is expecting a JSON data-type so we’ll have to convert our form data into a JSON object. I chose to do this with the jQuery Serialize Object script, which provides the serializeObject() method, and will convert our form into a JavaScript object. You can solve this problem however you’d like—as long as your data is structured like JSON!

Now, when someone submits your HTML form, their responses should be recorded in your Google Sheet. Sweet!

<form id="test-form">
<div>
<label>Field 1</label>
<input type="text" name="form_field_1" placeholder="Field 1"/>
</div>
<div>
<label>Field 2</label>
<input type="text" name="form_field_2" placeholder="Field 2"/>
</div>
<div>
<label>Field 3</label>
<input type="text" name="form_field_3" placeholder="Field 3"/>
</div>
<div>
<label>Field 4</label>
<input type="text" name="form_field_4" placeholder="Field 4"/>
</div>
<div>
<button type="submit"id="submit-form">Submit</button>
</div>
</form>
var $form = $('form#test-form'),
url = 'https://script.google.com/macros/s/abcdefghijklmnopqrstuvwxyz1234567890/exec'
$('#submit-form').on('click', function(e) {
e.preventDefault();
var jqxhr = $.ajax({
url: url,
method: "GET",
dataType: "json",
data: $form.serializeObject()
}).success(
// do something
);
})
/**
* jQuery serializeObject
* @copyright 2014, macek <[email protected]>
* @link https://github.com/macek/jquery-serialize-object
* @license BSD
* @version 2.5.0
*/
!function(e,i){if("function"==typeof define&&define.amd)define(["exports","jquery"],function(e,r){return i(e,r)});else if("undefined"!=typeof exports){var r=require("jquery");i(exports,r)}else i(e,e.jQuery||e.Zepto||e.ender||e.$)}(this,function(e,i){function r(e,r){function n(e,i,r){return e[i]=r,e}function a(e,i){for(var r,a=e.match(t.key);void 0!==(r=a.pop());)if(t.push.test(r)){var u=s(e.replace(/\[\]$/,""));i=n([],u,i)}else t.fixed.test(r)?i=n([],r,i):t.named.test(r)&&(i=n({},r,i));return i}function s(e){return void 0===h[e]&&(h[e]=0),h[e]++}function u(e){switch(i('[name="'+e.name+'"]',r).attr("type")){case"checkbox":return"on"===e.value?!0:e.value;default:return e.value}}function f(i){if(!t.validate.test(i.name))return this;var r=a(i.name,u(i));return l=e.extend(!0,l,r),this}function d(i){if(!e.isArray(i))throw new Error("formSerializer.addPairs expects an Array");for(var r=0,t=i.length;t>r;r++)this.addPair(i[r]);return this}function o(){return l}function c(){return JSON.stringify(o())}var l={},h={};this.addPair=f,this.addPairs=d,this.serialize=o,this.serializeJSON=c}var t={validate:/^[a-z_][a-z0-9_]*(?:\[(?:\d*|[a-z0-9_]+)\])*$/i,key:/[a-z0-9_]+|(?=\[\])/gi,push:/^$/,fixed:/^\d+$/,named:/^[a-z0-9_]+$/i};return r.patterns=t,r.serializeObject=function(){return new r(i,this).addPairs(this.serializeArray()).serialize()},r.serializeJSON=function(){return new r(i,this).addPairs(this.serializeArray()).serializeJSON()},"undefined"!=typeof i.fn&&(i.fn.serializeObject=r.serializeObject,i.fn.serializeJSON=r.serializeJSON),e.FormSerializer=r,r});
// original from: http://mashe.hawksey.info/2014/07/google-sheets-as-a-database-insert-with-apps-script-using-postget-methods-with-ajax-example/
// original gist: https://gist.github.com/willpatera/ee41ae374d3c9839c2d6
function doGet(e){
return handleResponse(e);
}
// Enter sheet name where data is to be written below
var SHEET_NAME = "Sheet1";
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
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;
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(e.parameter[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());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment