Send JSONP data to Google Apps script from javascript - javascript

I am trying to send data to a google app script, to create and insert data into a sheet. What I would like to happen is that the person using the page, will be the one asked to authorize the app (only allowed within the organization). So when authorized, the javascript on the page will send data via jsonp to an app script, which will process and generate a sheet, and then save it to the users drive, and show them the link (or open it up in a new tab).
But when I try this I am running into issues. Here is javascript in my app (not in googles html, my own app).
var foo = function(data) {
console.log('foo')
console.log(data)
}
var url = "https://script.google.com/a/macros/viedu.org/s/AKfycbzF6g9dAC5DI7Qtl0VD3QeYGsDbo43XxuVtoEYSHEA5_4yibYFN/exec"
console.log(url)
var data = {
"foo": "bar"
}
$.ajax({
"url": url,
// The name of the callback parameter
jsonp: "callback",
// Tell jQuery we're expecting JSONP
dataType: "json",
jsonpCallback: foo,
"data": data
})
.done(function(response) {
console.log('success')
console.log(response)
})
.fail(function(response) {
console.log('fail')
console.log(response)
})
and my app script:
function doGet(e) {
var cb = e.parameter.callback;
var data = JSON.stringify({"data":"bar"});
var outputStr = cb + "(" + data + ")";
return ContentService
.createTextOutput(outputStr)
.setMimeType(ContentService.MimeType.JAVASCRIPT);
}
and my response in chrome console:
fail
script.html:39 Object {readyState: 0, responseJSON: undefined, status: 0, statusText: "error"}
the response from the app script seems to be coming back as undefined. but im not sure why. If I try almost anything else in the jquery, I get errors stating it is trying to parse html/text and is invalid javascript. But I don't see what has to change in the app script as it looks fairly straight forward.

Replace this:
return ContentService.createTextOutput(outputStr).setMimeType(ContentService.MimeType.JAVASCRIPT);
with this:
var params = JSON.stringify(getr);
return ContentService.createTextOutput(params);

Related

Ajax url is undefined

I'm making a function to get a xml file and edit it. I've never done that before so I searched a good way to get an xml file. I decided to use ajax, but the file is never returned because the url is undefined.
EDIT :
I edited the code and made the treatment in the success function. Now there is no problem with this file.
Here is the update of the ajax part :
$.ajax({
type: 'GET',
url: 'allrtp.xml',
dataType: 'xml',
success: function(xml) {
//file = $.parseXML(xml);
// Editing the file to have the good dates
$(xml).find('StartDateTime').text(start);
$(xml).find('EndDateTime').text(end);
var strFile;
if (window.ActiveXObject) {
strFile = xml.xml;
} else {
strFile = (new XMLSerializer()).serializeToString(xml);
}
var encoded64 = Base64.encode(strFile); // Encoded in base64
var encodeURL = encodeURIComponent(encoded64); // Encoded URL
var AR = urlAR + encodeURL; // The URL to open
window.open(AR, '_blank');
}
})
Now all is working well about the xml file, I have a little problem with the window.open, which open my url but with %31 at the beggining, but it's another problem.
Thank you for your help !
file is undefined because you are declaring it inside a ajax success function
function openRecords(start, end) {
// Extraction of the xml file
var file;
$.ajax({
type: 'GET',
url: 'allrtp.xml',
dataType: 'xml',
success: function(xml) {
file = $.parseXML(xml);
},
error: function(ex) {
console.log(ex);
}
})
// Test
var start = '2016-02-15T12:57:00+01:00';
var end = '2019-02-16T13:57:00+01:00';
setTimeout(function(){
// Editing the file to have the good dates
file.find('StartDateTime').text(start);
file.find('EndDateTime').text(end);},1500);
}
Add an error callback:
error: function (ex) {}
Many things can be happening, you will get more info with the error callback. Probably you are querying an incorrect url. Do not trust that undefined upon url, see what returns your jquery ajax function. Maybe you should be querying something like '\files\xxx.xml'.
can you give me a picture of Network in your broswer? I want to know the URL is send or not:
1. F12 open your console
2. select the Network tab
3. refresh the broswer
4. check the request is send or not

POST using jQuery AJAX in HP servicemanager (HPSM)

I know this is a long shot, but I'm trying to make a POST with AJAX within the Javascript tool in HPSM. It's got very limited debugging capabilities so I'm stuck where it should be simple (or so I thought). From the syntax I've seen in other articles, calling that AJAX function should be right, but it doesn't seem to want to take it.
Thanks for any help
Here is the code I'm calling, and using jQuery library v1.11.2
var JSONdata = {
"eId": "xxx111",
"deviceToken": "111111111111",
"deviceType": "iphone",
"applicationName": "huds"
};
system.library.jQuery.ajax({
type: "POST",
url: 'http://place:11400/location/collaboration/notifications/register/',
data: JSONdata,
dataType: "json",
cache: false,
crossDomain: true,
processData: true,
success: function (data) {
alert(JSON.stringify(data));
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("error");
}
});
errors
Process panel calc.javascript in RAD format.cjavascript encountered error in line 5 (format.cjavascript,calc.javascript)
Cannot evaluate expression (format.cjavascript,calc.javascript)
Cannot evaluate expression (format.cjavascript,calc.javascript)
Cannot evaluate expression (format.cjavascript,calc.javascript)
Cannot evaluate expression (format.cjavascript,calc.javascript)
Script <UNKNOWN> line 20: ERROR TypeError: system.library.jQuery.ajax is not a function at char 1
Script 'jQuery' line 925: ERROR TypeError: document has no properties at char 1
Unrecoverable error in application: se.call.process on panel call.rad.1
Unrecoverable error in application: cm.update.save on panel call.master.upd
Unrecoverable error in application: format.cjavascript on panel calc.javascript
I'm assuming you have a ScriptLibrary called jQuery in your HPSM, right?
Try with
lib.jQuery.ajax(...
instead of system.library, regards.
not sure if you have imported the jQuery as a ScriptLibrary, but I think it will not work, because the code inside the jQuery Library includes some lines of code which are not valid for the HPSM.
Anyway...
To call an external external RESTful Service, you can use the doHTTPRequest() function in your ScriptLibrary.
What it is, what parameters are needed etc. can be found in the Programming Guide:
http://86.48.81.222:6080/classic/Content/Resources/PDF/sm_programming_guide.pdf
See Page 266 ...
Here an short example how it should work (it calls the REST API from the HPSM to create a new incident:
var objConfig = {
"url" : "http://place:11400",
"path" : "/location/collaboration/notifications/register/",
"connect_timeout" : 30,
"read_timeout" : 30
};
var objPostData = {
"eId": "xxx111",
"deviceToken": "111111111111",
"deviceType": "iphone",
"applicationName": "huds"
};
createRecord( objPostData );
/**
* Create a new Incident with the RESTful API
*
* #param {Object} objRecord Object with all required fields
*
*/
function createRecord( objRecord ) {
var JSON = system.library.JSON.json();
var arrHeaders = [];
//Content Type application/json is required
//otherwise we will get an 501 error
var typeHeader = new Header();
typeHeader.name = "content-type";
typeHeader.value = "application/json";
var arrHeaders = new Array();
arrHeaders.push(typeHeader);
//build url for the request
//Default Action for POST is "create" so we don't need
//to add the action again
var cRequestUrl = objConfig.url+objConfig.path;
//convert the given object to an json string
cPostBody = system.library.JSON2.toJSON(objRecord);
try {
//lets run the the HTTP request
//HTTP Command - url to execute - http header - POST Body
var rcRequest = doHTTPRequest( "POST", cRequestUrl, arrHeaders, cPostBody, objConfig.connect_timeout, objConfig.read_timeout );
//convert response json string back to an object
var objResponse = JSON.parse(rcRequest);
print( objResponse.toSource() );
} catch( e ) {
//something goes wrong
//check also http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
//to get the description of the given http response code like 401 etc.
//currently it's not possible (or i don't know how) to get the correct
//error response - for me it looks like that the HPSM has an filter
//which removes the response body if the response header is not 200
//if it's possible to use the reponse, we can use the same code
//as above JSON.parse() etc.
print("ERROR: \n"+e);
}
}
INFO1: Currently there is a limitation in the doHTTPRequest.
It can't handle the catch case correctly.
So even when there is an error, you will get the response as string.
And not the Object or whatever the response is.
INFO2: This example is based on my example to call the internal incident api.
I have modified it to your given data.
Code was created and tested successfully with HPSM 9.3+.
Hope this helps.
Greets
Marcus

Sending large javascript array to Web API

I am struggling with this issue for 2 days...
I have a JavaScript array (20,000K rows and 41 columns). It was originally received in javaScript through an ajax call as shown below,
var dataArray = [];
var dataRequest = {};
dataRequest.SearchCondition = 'some value';
$.ajax({
type: "POST",
url: "api/GetData/ProcessRequest",
dataType: 'json',
cache: false,
async: true,
crossDomain: false,
data: dataRequest ,
success: function (response) {
dataArray = response;
},
error: function (xhr, textStatus, errorThrown) {
dataArray = null;
}
});
In the application, the user will verify the data and send it back to Web API method.
I am trying to send the same data back (dataArray) to web api method but, it fails. Please see the code below,
Option 1: (failed - the request did not hit web api method)
var dataArrayJsonStr = JSON.stringify(dataArray);
$.ajax({
type: "POST",
url: "api/SendData/ProcessRequest",
dataType: 'json',
data: {'dataValue':dataArrayJsonStr },
success: function (response) {
alert('success');
},
error: function (xhr, textStatus, errorThrown) {
alert(errorThrown)
}
});
In IE 8, I am getting 'out of memory' exception popup. (most of our application users still have IE 8)
In Chrome, it crashes.
Option 2 tried: (don't know how to read the value)
I tried to send the same value to web api through XmllHttpRequest
var dataArrayJsonStr = JSON.stringify(dataArr);
var xmlRequest;
if (window.XMLHttpRequest) {
xmlRequest = new XMLHttpRequest();
}
xmlRequest.open("POST", "api/SendData/ProcessRequest", false);
xmlRequest.setRequestHeader('Content-Type', 'application/text');
xmlRequest.send("dataValue=" + dataArrayJsonStr);
Using Chrome, I am able to post the data successfully to Web API, I am seeing the content-length as '128180309'. But, I don't see the values. How do i get the values in Web API?
Please suggest me how to send large data back to web api from javascript.
Thanks,
Vim
I think you create overhead, maybe I wrong, you can edit me.
Did you really need send back all datas back or you just need send modified data?
Because in real life hard to imagine that user will review 20.000 of rows.
Good example is ExtJS stores, you can see example here
Key thing of stores that they send back to the server only modified or deleted data, it save browser, network and server resources.
Try to add more memory for API or more time excecution, also you can try return data in more small parts. Defining the number of parts to send.
Did you try to send the data by chunks?
I mean, you need to split it in small pieces and perform multiple number of requests.
For example, it can be like:
--HELLO SERVER. STARTING TRANSMITION FOR DATA SET #177151--
PIECE 1/13
PIECE 2/13
...
PIECE 13/13
--BUE SERVER--
So, it will take some time, but you can send any amounts of data without memory problems. If you're struggling with it for 2 days, I think you got some time to code it :)
UPD1: Client code example.
Here's an example of client code. This is a simple chunking algorithm.
Have to say I didn't test it, because it would take a lot of time to represent your situation.
So, you should read it and get the point.
You have a simple function, that takes you whole data set and callbacks for each response (to update your progress bar, e.g.), for successful finish and for error.
Hope, it will help you to make some problems.
Also, I can help you to build architecture on the server-side, but I need to know what technologies do you use.
function sendData(data, onEach, onFinish, onError) {
var CHUNK_SIZE = 1000;
var isFailed = false;
var chunkNum = 0;
var chunk, chunkStart, chunkEnd;
while(data.length + CHUNK_SIZE > chunkNum * CHUNK_SIZE) {
if(isFailed) {
return;
}
chunkStart = chunkNum * CHUNK_SIZE;
chunkEnd = chunkStart + CHUNK_SIZE + 1;
chunk = {
num: chunkNum,
data: data.slice(chunkStart, chunkEnd)
};
ajaxCall(chunk);
chunkNum++;
}
function ajaxCall(data) {
$.ajax({
type: "POST",
url: "api/GetData/ProcessRequest",
dataType: 'json',
async: true,
data: dataRequest ,
success: function (response) {
onEach(data, response);
},
error: function (xhr, textStatus, errorThrown) {
isFailed = true;
onError(arguments);
}
});
}
}

Setting string in javascript function in ASP.NET MVC give NullReferenceException

Inside my MVC view I have javascript that is executed by a button click. I'm trying to set a string to a random set of characters which I can get to work fine but when I try and set that string to 'randomchars' string inside the javascript I get a NullReferenceException when I try and run the view.
Below is the code snippet, the CreateRString is where the model parameter (RString) is set to the random string.
<script type="text/javascript">
function showAndroidToast(toast) {
var url = '#Url.Action("CreateRString", "Functions")';
$.ajax({ url: url, success: function (response) { window.location.href = response.Url; }, type: 'POST', dataType: 'json' });
var randomchars = '#(Model.RString)';
}
</script>
Is the syntax correct? I'm not too sure why it's getting the NULL.
The javascript is executed after the page been delivered to the client (i.e. web browser). Your razor code here is executed on the server before the page is sent to the client. Therefore, the ajax method will execute after you try to access Model.RString
To fix this you can either call CreateRString on the server, or you can set randomchars by using the response in the success callback.
To explain option 2 a bit further. You could do something like this:
//Action Method that returns data which includes your random chars
public JsonResult CreateRString()
{
var myRandomChars = "ABCDEF";
return new JsonResult() { Data = new { RandomChars = myRandomChars } };
}
//The ajax request will receive json created in the CreateRString method which
//contains the RandomChars
$.ajax({ url: url, success: function (response) {
var randomchars = response.Data.RandomChars;
window.location.href = response.Url;
}, type: 'POST', dataType: 'json' });
More specifically, the razor calls #Url.Action("CreateRString", "Functions") and #(Model.RString) execute first on the server.
Then showAndroidToast executes in the client's browser when you call it.

Posting to Twitter through OAuthSimple.js

I've been stuck on this one for a while. I'm trying to use OAuthSimple.js to interact with Twitter in a Chrome extension I've written.
The signing process seems to work fine for requests to retrieve a user's statuses, but I can't seem to construct a request that will successfully authenticate when I try to retweet, reply, or mark a tweet as favorite.
I'm following the guides here. I have also tried numerous ways of structuring the request, and comparing the request contents against the output of the OAuth tool provided by Twitter ( which seems to check out ), but I'm still getting 401 errors and generic "We couldn't authenticate you" responses.
Here's how I'm trying to form the request:
var sendTwitterRequest = function(url, params, method, callback) {
var request = null;
if ( localStorage.twitterAuthToken ) {
OAuthSimple().reset();
request = OAuthSimple(TwitterConsumerKey,TwitterConsumerSecret).sign({
action:method,
method:"HMAC-SHA1",
dataType:"JSON",
path:url,
parameters:params,
signatures:{
oauth_version:'1.0',
oauth_token:localStorage.twitterAuthToken,
oauth_secret:localStorage.twitterAuthVerifier
}
});
console.log(request);
$j.ajax({
url:request.signed_url,
type:method,
data:request.parameters,
success:callback
});
}
};
Then, making calls into this method like this:
// this works, I get the data and can do stuff with it
sendTwitterRequest('http://api.twitter.com/1/statuses/user_timeline.json?user_id=',null,'GET',someMethod());
// this fails and throws a 401 error every time
sendTwitterRequest("https://api.twitter.com/1/statuses/retweet/"+tweetKey+".json",null,'POST',someOtherMethod());
Am I missing something? Thanks in advance!
It turns out the requests I am creating are fine, I just needed a final one to exchange request tokens for OAuth tokens. I thought this step was covered when the user was prompted for input, but turns out I was wrong.
I also ended up switching from OAuthSimple.js to just OAuth.js, on account of the fact that I could only get OAuth.js to process both the token requests and the timeline requests.
Some of this is pretty specific to what my application is doing, so you will probably need to modify it.
The new sendTwitterRequest method:
var sendTwitterRequest = function(options){
var accessor={
consumerSecret:TwitterConsumerSecret
};
var message={
action:options.url,
method:options.method||"GET",
parameters:[
["oauth_consumer_key",TwitterConsumerKey],
["oauth_signature_method","HMAC-SHA1"],
["oauth_version","1.0"]
]
};
if(options.token){
message.parameters.push(["oauth_token",options.token])
}
if(options.tokenSecret){
accessor.tokenSecret=options.tokenSecret
}
for(var a in options.parameters) {
message.parameters.push(options.parameters[a])
}
OAuth.setTimestampAndNonce(message);
OAuth.SignatureMethod.sign(message,accessor);
try {
$j.ajax({
url:message.action,
async:options.async||true,
type:message.method||'GET',
data:OAuth.getParameterMap(message.parameters),
dataType:options.format||'JSON',
success:function(data) {
if (options.success) {options.success(data);}
}
});
} catch ( e ) {
}
};
And the methods that depend on it:
// asks Twitter for an oauth request token. User authorizes and the request token is provided
requestTwitterToken = function() {
// this is semi-specific to what my extension is doing, your callback string may need
// to be slightly different.
var callbackString = window.top.location + "?t=" + Date.now();
var params = [
[ 'oauth_callback', callbackString ]
];
sendTwitterRequest({
url: "https://api.twitter.com/oauth/request_token",
method: 'POST',
parameters: params,
format: 'TEXT',
success: function(data) {
var returnedParams = getCallbackParams(data);
if ( returnedParams.oauth_token ) {
chrome.tabs.create({
url:"https://api.twitter.com/oauth/authorize?oauth_token=" + returnedParams.oauth_token
});
}
},error:function( e ) {
console.log( 'error' );
console.log( e );
}
});
};
// exchanges the Twitter request token for an actual access token.
signIntoTwitter = function(token, secret, callback) {
var auth_url = "https://api.twitter.com/oauth/access_token";
var authCallback = function(data) {
var tokens = getCallbackParams(data);
localStorage.twitterAuthToken = tokens.oauth_token || null;
localStorage.twitterAuthTokenSecret = tokens.oauth_token_secret || null;
callback();
};
try {
sendTwitterRequest({url:auth_url, method:'POST', async:true, format:'TEXT', token:token, tokenSecret:secret, success:authCallback});
} catch ( e ) {
console.log(e);
}
};
With this, the steps are as follows:
ask Twitter for a token ( requestTwitterToken() ) and provide a callback
in the callback, check to see if a token is provided. If so, it's an initial token
pass the token back to Twitter and open the Twitter auth page, which allows the user to grant access
in the callback to this call, see if an access token was provided
exchange the request token for an access token ( signIntoTwitter() )
After that, I simply use the sendTwitterRequest() method to hit Twitter's API to fetch the timeline and post Tweets.

Categories