JQuery AJAX - Sending a JSONP form with attached files - javascript

I'm working in a contact form for our clients that creates webpages with us with their own domain. We offer them a hosting and a web editor to create their websites. When they create a contact form in their websites, whoever that visit their websites and fills a form to contact them, it is sent to our platform and it sends a email to our client notifying him/her that someone filled his/her contact form.
To make it work, we are using a jsonp ajax call in our clients webpage to send the form to our platform, which performs the email template and sends the email.
The problem now is that our clients asked to add a input field type to allow whoever that visits their page to attach a file to the form, so they can see an attached file in the contact notification email, but I can't find a way to do it using jsonp because it uses GET method to create a crossdomain request and everthing I've serarched in Stackoverflow, talks about using a POST method to send files with a form and get form data as new FormData().
Here is the code I had before trying the implementation:
var $form = $('form');
$form.submit(function(e){
e.preventDefault();
$.ajax({
url: url,
dataType: "jsonp",
data: $form.serialize(),
beforeSend: function () {
$form.data('allowSending', false); // To prevent multiple sendings while processing
},
success: function(data) {
alert(data.message);
$form.data('allowSending', true);
}
});
});
This is the code that I've tried, but it's not handled as expected:
var $form = $('form');
$form.submit(function(e){
e.preventDefault();
$.ajax({
url: url,
processData: false,
contentType: false,
dataType: "jsonp",
data: new FormData(this),
beforeSend: function () {
$form.data('allowSending', false); // To prevent multiple sendings while processing
},
success: function(data) {
alert(data.message);
$form.data('allowSending', true);
}
});
});
When it sends the filled form with the code that I've tried (the second one), tries to send the data as an object through the URL, like: ?callback=jQuery111107622947758095266_1459251318335&[object%20FormData]&_=1459251318336
How can I solve this?
Thanks in advance.
Regards.
PS: To make things harder, forms are completely dynamic, so if a solution is passing parameters manually, etc. it must be in a dynamic way with a for loop.

The short answer is that you can't.
Your attempt is failing because, since JSONP makes a GET request, contentType is ignored and data is treated as a string (since you said processData: false).
As you say, JSONP works by encoding everything in the URL. While it is possible to use the File API to read the content of the file and convert it into a base64 encoded string, that will exceed URL length limits for all but the smallest of files which makes it impractical.
Stop using JSONP. It is a, frankly dirty, hack that was used to sneak around the Same Origin Policy. We now have CORS, which is a standard, non-hacky, highly flexible method to selectively disable the same origin policy. One of the advantages of its flexibility is that you can make cross-origin POST requests using it.

Related

Submit a form to DJANGO from Phonegap Application using JAVAScript

I have written a Phonegap application and I would like to know how can I submit a form to Django using Javascript or Jquery. I have already implemented a JSON API using Tastypie.
Can anybody provide me with some ideas, or any guidance on how to implement such a function?
You just have to do ajax call to tastypie api url in the below format.
$.ajax({
type: 'POST',
url: site_url+'api/v2/user/login/',
data: '{"username": "developer", "password":"imagine2"}',
processData: false,
crossDomain: true,
success: function (response, textStatus, xhr) {
console.log('jquery worked');
//results=JSON.stringify(response);
setCookie( "sessionid", response.sessionid);
setCookie( "app_version", response.app_version);
window.location.href = 'home/';
$('#overlay').hide();
},
error: function (res) {
msg = (res.responseText) ? res.responseText : res.statusText;
console.log(msg+",res.status="+res.status);
alert(msg);
},
dataType: "json",
contentType: "application/json; charset=utf-8"
});
Also you need to enable cross domain.
There are multiple ways to do this. Since you are using an API with tastypie I would suggest not submitting the form itself, but extracting the form data before submitting the form with JavaScript. On submit you pass the data you want to submit in the request body to your API endpoint.
As an example you could have an api endpoint for blog entries, lets say its http://example.com/api/v1/entry. Considering your API allows cross-domain requests (e.g. via CORS) you could do something simple as this to "submit" your form (e.g. creating a new entry):
$('#myForm #mySubmitButton').click(function() {
$.post('http://example.com/api/v1/entry', $('#myForm').serialize(), function(data) {
// deal with the response data
}
});
I am not sure tastypie supports this kind of data structure. A little longer version of this could be to do something like this (here I am sure tastypie does support it), which submits the data as a JSON:
$('#myForm #mySubmitButton').click(function() {
var data = {'title': $('#myForm #titleInput').val(), 'description': $('#myForm #descriptionInput').val()};
$.post('http://example.com/api/v1/entry', data, function(data) {
// deal with the response data
}
});
This examples do not deal with form validation, error handling etc.. You could have look into tastypie validation for more details and potentially also add frontend specific validation with HTML5. I would also suggest you to use a more sophisticated JavaScript framework like AngularJS for single page apps like a PhoneGap app. JQuery will bloat your app soon, when it grows.

How do I do an ajax call to a database using Javascript, a URL and a key

I have been given a url of type xxxx.xxxxx.com as well as a key of type FGHyehgvc787vbhj
in order to gain read-only access to an sql database and retrieve data from it using javascript.
I have no prior experience with databases and maybe my question will sound completely stupid but I was wondering how can I combine the above information in order to get access to the database (e.g. do an ajax call and retrieve data from it..)
I'm familiar with doing ajax calls to a webpage and getting data from it using jQuery, as in :
$.ajax(/*url of website*/, function (data)
{
var dataRetrieved = $(data);
// do something with the data retrieved...
});
so I was wondering whether there is something equivalent to the above when it comes to making an ajax call to a database, using however a key.
Thank you for any help, and please delete this post if you find it completely pointless and excuse me in advance for that by the way.
It is usually very bad design to allow client side code to interact with your database in any way. This can be a huge security issue. Generally you will want your server side code to do this (e.g PHP, node, etc.). You would send a request to your server with client side code, and the server side code would do the actual work of updating the database.
you can create a wcf service and call that service through ajax, that wont be huge security issue.
try this
$.ajax({
cache: false,
type: "GET",
async: false,
data: {},
url: http:xxxxxxxxxxxx.svc/webBinding/Result?metaTag=" + meta,
contentType: "application/json; charset=utf-8",
dataType: "json",
crossDomain: true,
success:function(result){},
error: function(){alert(err);}
});
Use this
$.ajax({
url: 'path/to/server-side/script.php', /*url*/
data: '', /* post data e.g name=christian&hobbie=loving */
type: '', /* POST|GET */
complete: function(d) {
var data= d.responseTXT;
/* Here you can use the data as you like */
$('#elementid').html(data);
}
});
Hope this helps...

jQuery POST to webservice via CORS

I have read a lot of topics about CORS & Javascript and about changing the headers in your post but I can't find the right example I am looking for.
So I'm going to first up start with explaining the situation:
I can not change anything to the webserver since this is out of my reach (It's a SAP Cloud Portal)
I can only change the POST code, so I can only control what I send.
The problem I have is described in the following Post:
jQuery $.ajax(), $.post sending "OPTIONS" as REQUEST_METHOD in Firefox
--> My FF & Chrome Headers send a METHOD OPTIONS instead of METHOD POST.
I have written example code that works in IE but not in FF & Chrome:
var dataString = "<result><firstname>example</firstname><lastname>ThisIsSparta</lastname></result>";
var urlString = "http://delyo001.you.local:8000/sap/bc/youconsulting/ws/rest/anonymous/z_names_post";
//Add TO SAP.
var aData =
jQuery.ajax({
type: "POST",
contentType: "application/xml",
url: urlString, // for different servers cross-domain restrictions need to be handled
data: dataString,
dataType: "text",
success: function(xml) { // callback called when data is received
//oModel.setData(data); // fill the received data into the JSONModel
alert("success to post");
},
error: function(xml) { // callback called when data is received
//oModel.setData(data); // fill the received data into the JSONModel
alert("fail to post");
}
});
});
Or
var invocation = new XMLHttpRequest();
var url = 'http://delyo001.you.local:8000/sap/bc/youconsulting/ws/rest/anonymous/z_names_post';
var body = '<result><firstname>perthyrtyrtygop</firstname><lastname>sparta</lastname></result>';
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.send(body);
I have found 2 ways to fix this but without any examples:
- do something with a proxy?
- send specific headers
More information about my problem can be found at:
- http://scn.sap.com/message/13697625#13697625
If you can't set the right headers on the server-side and you can't modify the response for jsonP you should indeed use a proxy.
A proxy script is a sort of middleware. You make a request to the script the script gets the data, and returns it to you. For example php proxy. You can make the same thing in asp, jsp, flash or even java applet.
Now you have your SAP service, a proxy (php)file in a your prefered location, and your local javascript in the same domain as the proxy. You don't even need CORS.
If you want to put the proxy in another domain you have to make sure the php file sends the right headers. (Access-Control-Allow-Origin yourdomain or Access-Control-Allow-Origin * for allow all)

AD FS 2.0 Authentication and AJAX

I have a web site that is trying to call an MVC controller action on another web site. These sites are both setup as relying party trusts in AD FS 2.0. Everything authenticates and works fine when opening pages in the browser window between the two sites. However, when trying to call a controller action from JavaScript using the jQuery AJAX method it always fails. Here is a code snippet of what I'm trying to do...
$.ajax({
url: "relyingPartySite/Controller/Action",
data: { foobar },
dataType: "json",
type: "POST",
async: false,
cache: false,
success: function (data) {
// do something here
},
error: function (data, status) {
alert(status);
}
});
The issue is that AD FS uses JavaScript to post a hidden html form to the relying party.
When tracing with Fiddler I can see it get to the AD FS site and return this html form which should post and redirect to the controller action authenticated. The problem is this form is coming back as the result of the ajax request and obviously going to fail with a parser error since the ajax request expects json from the controller action. It seems like this would be a common scenario, so what is the proper way to communicate with AD FS from AJAX and handle this redirection?
You have two options.
More info here.
The first is to share a session cookie between an entry application (one that is HTML based) and your API solutions. You configure both applications to use the same WIF cookie. This only works if both applications are on the same root domain.
See the above post or this stackoverflow question.
The other option is to disable the passiveRedirect for AJAX requests (as Gutek's answer). This will return a http status code of 401 which you can handle in Javascript.
When you detect the 401, you load a dummy page (or a "Authenticating" dialog which could double as a login dialog if credentials need to be given again) in an iFrame. When the iFrame has completed you then attempt the call again. This time the session cookie will be present on the call and it should succeed.
//Requires Jquery 1.9+
var webAPIHtmlPage = "http://webapi.somedomain/preauth.html"
function authenticate() {
return $.Deferred(function (d) {
//Potentially could make this into a little popup layer
//that shows we are authenticating, and allows for re-authentication if needed
var iFrame = $("<iframe></iframe>");
iFrame.hide();
iFrame.appendTo("body");
iFrame.attr('src', webAPIHtmlPage);
iFrame.load(function () {
iFrame.remove();
d.resolve();
});
});
};
function makeCall() {
return $.getJSON(uri)
.then(function(data) {
return $.Deferred(function(d) { d.resolve(data); });
},
function(error) {
if (error.status == 401) {
//Authenticating,
//TODO:should add a check to prevnet infinite loop
return authenticate().then(function() {
//Making the call again
return makeCall();
});
} else {
return $.Deferred(function(d) {
d.reject(error);
});
}
});
}
If you do not want to receive HTML with the link you can handle AuthorizationFailed on WSFederationAuthenticationModule and set RedirectToIdentityProvider to false on Ajax calls only.
for example:
FederatedAuthentication.WSFederationAuthenticationModule.AuthorizationFailed += (sender, e) =>
{
if (Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
{
e.RedirectToIdentityProvider = false;
}
};
This with Authorize attribute will return you status code 401 and if you want to have something different, then you can implement own Authorize attribute and write special code on Ajax Request.
In the project which I currently work with, we had the same issue with SAML token expiration on the clientside and causing issues with ajax calls. In our particular case we needed all requests to be enqueud after the first 401 is encountered and after successful authentication all of them could be resent. The authentication uses the iframe solution suggested by Adam Mills, but also goes a little further in case user credentials need to be entered, which is done by displaying a dialog informing the user to login on an external view (since ADFS does not allow displaying login page in an iframe atleast not default configuration) during which waiting request are waiting to be finished but the user needs to login on from an external page. The waiting requests can also be rejected if user chooses to Cancel and in those cases jquery error will be called for each request.
Here's a link to a gist with the example code:
https://gist.github.com/kavhad/bb0d8e4a446496a6c05a
Note my code is based on usage of jquery for handling all ajax request. If your ajax request are being handled by vanilla javascript, other libraries or frameworks then you can perhaps find some inspiration in this example. The usage of jquery ui is only because of the dialog and stands for a small portion of the code which could easly be swapped out.
Update
Sorry I changed my github account name and that's why link did not work. It should work now.
First of all you say you are trying to make an ajax call to another website, does your call conforms to same origin policy of web browsers? If it does then you are expecting html as a response from your server, changedatatype of the ajax call to dataType: "html", then insert the form into your DOM.
Perhaps the 2 first posts of this serie will help you. They consider ADFS and AJAX requests
What I think I would try to do is to see why the authentication cookies are not transmitted through ajax, and find a mean to send them with my request. Or wrap the ajax call in a function that pre authenticate by retrieving the html form, appending it hidden to the DOM, submitting it (it will hopefully set the good cookies) then send the appropriate request you wanted to send originally
You can do only this type of datatype
"xml": Treat the response as an XML document that can be processed via jQuery.
"html": Treat the response as HTML (plain text); included script tags are evaluated.
"script": Evaluates the response as JavaScript and evaluates it.
"json": Evaluates the response as JSON and sends a JavaScript Object to the success callback.
If you can see in your fiddler that is returning only html then change your data type to html or if that only a script code then you can use script.
You should create a file anyname like json.php and then put the connection to the relayparty website this should works
$.ajax({
url: "json.php",
data: { foobar },
dataType: "json",
type: "POST",
async: false,
cache: false,
success: function (data) {
// do something here
},
error: function (data, status) {
alert(status);
}
});

How do I ensure jQuery ajax call does not send a local copy of file?

$.ajax({
type: 'GET',
url: "string.txt",
cache: false,
success: function(str){
alert("Data is: "+ str);
}
});
In this example, string.txt is sent to the cache (\Temporary Internet Files)
How do I ensure that the file is not sent. I do not want copy to be sent.
Only a read from the server. Am I missing an option?
I set cache to false but that does not block it from being sent to client.
For example, ajax POST does not send a local copy.....
Here is some background info to what i am trying to do, but with jQuery.
I am curious as to why the standard ajax post seems to have the desired functionality I am looking for and am unable to do that with jQuery?
Thanks
Or set a no cache header server-side.

Categories

Resources