Post through google app scripts - ajax

I am trying to post from a HTML form to a Google sheet. I am currently just trying to write the code in the Google App script but an error states "Script function not found: doGet" and I cannot figure out what to do. My code is below:
function myFunction() {
var SHEET_NAME = "Sheet1";
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
function doGet(e){
return handleResponse(e);
}
function doPost(e){
return handleResponse(e);
}
function handleResponse(e) {
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
try {
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var sheet = doc.getSheetByName(SHEET_NAME);
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());
}
}
Any help would be much appreciated.

You don't need to wrap the whole script in "myFunction()", if you remove that function with his corresponding bracket it should work just fine.
Remove this => function myFunction() { --from the beginning.
And this => } -- from the end.

You probably need to use ContentService
Google Documentation - Content Service

Related

Submitting data to google sheet with multiple tab sheets

I'm referencing this article "How to Submit an HTML Form to Google Sheets…without Google Forms", it worked perfectly for me for only a Google Sheet with one tab.
Need help how to dynamically select what sheet tab the data should be written in the case the google sheet has multiple tabs. I'm using Ajax to submit google sheet btw.
Here's the call by the Ajax:
var $form = $('form#test-form'),
url = 'https://script.google.com/macros/s/MyScript/exec'
$('#submit-form').on('click', function(e) {
e.preventDefault();
var jqxhr = $.ajax({
url: url,
method: "GET",
dataType: "json",
data: $form.serializeObject()
}).success(
// do something
);
})
The code on google sheet web app
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());
}
If there is a way to change the variable SHEET_NAME dynamically then I think it will be good. Thanks

Get Specific Data From ngStorage

I have a bunch of data on JSON using LocalStorage from ng-storage like this,
[Object { judul="Just", isi="Testing"}, Object { judul="To", isi="Get"}, Object { judul="Specific", isi="Data"}]
but I want to get one specific data to get the "isi" value, how to do that ?
You can do this by adding a get function to your factory
for example :
.factory ('StorageService', function ($localStorage) {
$localStorage = $localStorage.$default({
things: []
});
var _getAll = function () {
return $localStorage.things;
};
//-----
var _get = function (isi) {
for( var i = 0; i < $localStorage.things.length ; i++ ){
if( $localStorage.things[i].isi === isi ){
return $localStorage.things[i];
}
}
}
return {
getAll: _getAll,
get : _get
};
})
and in your controller you can get the specific data by passing the id of your object
var objectInlocal = StorageService.get(Thing.isi);

Get Data from parse.com Promises

I am trying to use parse.com promises to retrieve job data as well as user relation data associated with the job. I have a function that returns promises but not job data. How do I get the job & employee information from the returned promises?
Logically I want to:
1) Query Parse to get array of jobs
2) For each job, query Parse again to get the employee relation information
3) Create local object that contains job & employee details
4) Add each job object to local array
5) Load table with array of objects once all information has been retrieved from Parse
I can do steps 1-4 but I can't figure out how to wait until all information has been retrieved from Parse to refresh the local table.
function getJobPromises (){
var promises = [];
var Job = Parse.Object.extend("Job");
var query = new Parse.Query(Job);
query.equalTo("company", company);
query.notEqualTo("isDeleted", true);
query.limit(1000); // raise limit to max amount
query.find().then(function(results) {
// Create a trivial resolved promise as a base case.
var promise = Parse.Promise.as();
_.each(results, function(result) {
// For each item, extend the promise with a function to add it to the job array
promise = promise.then(function() {
// Return a promise that will be resolved when the job details have been added to the array
var object = result;
promises.push(getEmployeeName(object));
allJobDataArray = promises;
});
});
return Parse.Promise.when(promises);
}).then(function() {
// Every job has been retrieved
console.log("All items have been returned. Refresh table...");
console.log(allJobDataArray);
});
}
The function that does the relational query to get the users associated with the job
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
console.log(employeeNameArray);
}
},
error: function(error){
response.error(error);
}
});
}
Update
It is now working thanks to #eduardo
I have a public array to hold the job objects.
var jobObjectsArray = [];
In the getEmployeeName function I am creating the job objects and adding them to that array
function getJobPromises (){
var promises = [];
var Job = Parse.Object.extend("Job");
var query = new Parse.Query(Job);
query.equalTo("company", company);
query.notEqualTo("isDeleted", true);
query.limit(1000); // raise limit to max amount
query.find().then(function(results) {
_.each(results, function(result) {
promises.push(getEmployeeName(result));
});
return Parse.Promise.when(promises);
}).then(function(allJobDataArray) {
// allJobDataArray should be actually an Array of Array
console.log(jobObjectsArray);
refreshTable();
});
}
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return new Promise(
function(resolve, reject) {
rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
var objAllJobs = new Object();
objAllJobs["jobId"] = jobObject.id;
objAllJobs["location"] = jobObject.get("location");
objAllJobs["startTime"] = jobObject.get("startTime");
objAllJobs["employee"] = employeeNameArray;
jobObjectsArray.push(objAllJobs);
}
console.log(employeeNameArray);
resolve(employeeNameArray);
},
error: function(error){
reject(error);
}
});
}
);
There was a few incorrect uses of the promise concept. I will go through them, but first here is the final code:
function getJobPromises (){
var promises = [];
var Job = Parse.Object.extend("Job");
var query = new Parse.Query(Job);
query.equalTo("company", company);
query.notEqualTo("isDeleted", true);
query.limit(1000); // raise limit to max amount
query.find().then(function(results) {
_.each(results, function(result) {
promises.push(getEmployeeName(result));
});
return Parse.Promise.when(promises);
}).then(function(allJobDataArray) {
// allJobDataArray should be actually an Array of Array
console.dir(allJobDataArray);
console.log(allJobDataArray[0]);
});
}
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
}
console.log(employeeNameArray);
return employeeNameArray;
},
error: function(error){
response.error(error);
}
});
}
"Parse.Promise.as()" should be used only if you have a value that you want to return as a promise. Something like:
Parse.Promise.as("my value").then(function(foo) {
console.log(foo) // "my value"
});
So if your "getEmployeeName" function is returning a promise, which means that this "rQuery.query().find" returns a promise, you don't have to create a new promise or use the "Parse.Promise.as()", it is already a promise and you can push it to the promises array.
Another problem was that you were not return anything in the "getEmployeeName" method callback. Take a look into my version, I'm returning "employeeNameArray".
My version will only work if this "rQuery.query().find" method returns a promise. If that is not the case, you can create a new promise using its callbacks like this:
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return new Promise(
function(resolve, reject) {
rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
}
console.log(employeeNameArray);
resolve(employeeNameArray);
},
error: function(error){
reject(error);
}
});
}
);
}
Please notice this "new Promise()" depends on the browser support of Promise, I don't know if Parse has an equivalent. Anyways you can use it with a polyfill that implements the necessary code if the browser has no support.
More about standard promises: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Polyfill: https://github.com/jakearchibald/es6-promise/
Hope this helps.

Recursive Query to get more than 1000 results outside Parse.cloud impossible?

I'm in need to fetch over 1000 elements from a Class.
So I tried following advices on this topic, but something is not working correctly, and already spent the whole day to find a solution.
Parse.Cloud.define("getFollow", function(request, response) {
var following = [];
var user = request.params.user;
user.fetch().then(function(result) {
if (!result.get('following')) {
following = getFollowing({
'user': user
});
}
}).then(function() {
response.success(following);
}, function(error) {
response.error(error);
});
});
function getFollowing(request) {
var count = 0;
var skip = request.skip || 0;
var limit = 1000;
var following = request.following || [];
var Follow = Parse.Object.extend('follow');
var query = new Parse.Query(Follow);
query.limit(limit);
query.ascending('objectId');
query.skip(skip * limit);
query.equalTo('followers', request.user);
query.find().then(function(results) {
skip+= 1;
count = results.length;
/* I can't see any DEBUG, seems nothing is queried */
console.log('[DEBUG] Check <count>: ' + count);
return Parse.Promise.when(results.map(function(result) {
following.push(result.get('followed'));
}));
}).then(function() {
if(count >= limit) {
following = getFollowingUsers({
'user': request.user,
'skip': skip,
'following': following
});
}
}).then(function() {
return following;
}, function(error) {
return error;
});
}
I tried many variant of this code, trying to return the very first result of the query, rather than a collection. I also tried to remove all contraints, but even so, my query seems not to be run.
I also tried to use a Cloud.code function to make this recursively using only Parse.Cloud, but if I do that, I'm having a message Too many recursive calls into Cloud Code
What did I do wrong with this logic ?

What is the correct JSON structure for this while loop?

I'm a little new to JSON so trying to understand what is the best way to do this. I have two variables: postcode and energyrating that I want to put into JSON and then parse to a for loop.
I can get it to work with one variable but when I have two it doesn't work.
Here is my JSON:
header('Content-type: application/json');
$postcodeArray = array('postcodes' => array("E6 2JG","SE1 2AQ","DA1 1DZ"), 'energyrating' => array("A","B","C","D","E","F","G"));
die(json_encode($postcodeArray));
Here is my jQuery:
function addNew(postcodes) {
if(postcodes.length > 0) {
for(var i = 0; i < postcodes.length; i++) {
var address = postcodes[i];
var rating = energyrating[i];
geocoder.geocode( { 'address': address }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var image = '../img/markers/' + rating + '.png';
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon: image
});
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
} else {
alert("Sorry, no data was found.");
}
}
How do I get this to work with both variables?
What does not work exactly ?
Reading your code, I would say there is an error into your code. The energyrating argument is missing into your addNew function:
function addNew(postcodes, energyrating) {
Assuming that you call your function like this:
addNew(jsonData.postcodes, jsonData.energyrating);
Use json variables to store the data like that :
$postcodeArray = '{"postcodes":{"0":E6, "1":"2JG", "3":"SE1 2AQ","4":"DA1 1DZ"}, "energyrating":{"0":"A","1":"B","2":"C","3":"D","4":"E","5":"F","6":"G"}}';
In the place of
$postcodeArray = JSON.parse('postcodes' => array("E6 2JG","SE1 2AQ","DA1 1DZ"), 'energyrating' => array("A","B","C","D","E","F","G"));
And you can access the values.
Or try json_decode(postcodes) in the function addNew in first line.

Resources