Retrieving response from remote server after uploading a file in iframe - javascript

I have a form that uploads a file in an firame to a remote server. As a result at the submission url server returns json data with the result of operation, which my iframe catches.
{'result': 'true' or 'false'}
Now I'd like to retrieve this json as the callback of my iframe. I know that I need jsonp to achieve this since it's a cross-site call. Here's my function with sample code from IBM' site :
function fileUploadFunction(){
var fileUploadForm = $('#file_upload_form');
fileUploadForm.attr('action', uploadURL);
fileUploadForm.submit();
$('#upload_target').load(function () {
alert("IFrame loaded");
$.getJSON(uploadUrl+"&callback=?", function(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
});
});
};
But here few problems arise. First - my uploadUrl is just "http://something/" . Do I need it to support calls with $callback= suffix ?
Secondly - server gives response only as a result to file upload. So I need to get the result that is stored in my iframe and not at the specified url. How to solve this ?
Here's the link. Notice hidden iframe inside the form. Result from server shows there. :
http://ntt.vipserv.org/artifact/
EDIT
I've previously tried :
$('#upload_target').load(function () {
var ret = frames['upload_target'].document.getElementsByTagName("body")[0].innerHTML;
var data = eval("("+ret+")");
});
But it raises 'permissions denied' error.

This is easily done with easyXDM and there is actually a blog post about this exact use case here.
In essence what it does is use cross-domain messaging to relay the response to the invoking document.
Update: Here is a link for this in action, the source can be found at github, the files are prefixed 'upload_'.

Sean's easyXDM recommendation is a great option (& should probably be marked as correct), but I wanted to suggest another light-weight solution that I haven't seen anyone use.
In cases where you're posting to a hidden iframe on another domain & just need a single response back (not two-way communcation), you could pass a message from the iframe to the parent using a busted url. Here's an example:
the parent loads an iframe on different domain
the parent polls myframe.contentWindow.location.href (constantly getting Permission denied errors since the frame is on another domain)
iframe processes, then redirects to
http://parentdomain.com/pagethatdoesnotexist?{'result':'ok'}
iframe gets a 404 but now the location is available to the parent
the parent reads the message from the iframe's URL

one possible solution could be to set the name of the iframe with pure js. This name could be read from the wrapping parent page.

Looks to me that your code will request uploadURL twice: first, .submit() do a POST request to upload the file and the result is shown in the iframe as a webpage; second, .getJSON() do a GET request and the result is executed as javascript in <script>. You will realize this if you open up Firebug while testing your app.
Since two of the requests are independent, I have no idea how .getJSON() will give you any information about the file you just uploaded with .submit().
For these kind of cross-domain communication, I would suggest using postMessage; otherwise you will need to change you application workflow to do everything in the iframe after file have uploaded; e.g. do <script>alert('Submission accepted');</script> in the iframe.
What are you trying to do after a user have successfully upload a file?

dont use .html() at all.
I used
jQuery('.someElement')
and it worked for me. you can save the result in a variable and insert it in new element
e.g
var = jQuery('.someElement');
jQuery('.newElement').html(var);

Related

Sending cross-origin iFrame content over postMessage fails

First of all, I know that the topic of accessing iFrame Elements cross-domain is a tricky topic and I might be going with this nowhere.
I have a Google Forms embedded in my app that I need to set up in a way to tell me when a user has submitted his/her response. I already tried lots of things but the most optimistic way that could work would be just to read the HTML of the iFrame when the last page has been loaded saying that the response was submitted.
Therefore, I was looking for solutions on how to simply read any kind of snippet of the iFrame's content and I came across this comment in another thread:
https://stackoverflow.com/a/32265508/3856569
I'm trying reading the content of the iFrame as suggested in the comment and sending it to the parent windows via postMessage like so:
$(document).ready(function() {
document.getElementById("googleForm").addEventListener("load",
function() {
var message = document.getElementById("googleForm");
parent.postMessage(JSON.parse(JSON.stringify(message)), '*')
});
})
and the parent-window reads the message like so:
function receiveMessageGoogleForm (event) {
console.log(event)
}
//Listen for message events
window.addEventListener("message", receiveMessageGoogleForm, false);
However, the data property of the event object upon receiving the message seems to be empty.
Is this another inbuilt mechanism to avoid reading any kind of a cross-origin iFrame or am I missing something here?
Forget about postMessage for a moment.
var message = document.getElementById("googleForm");
var result = JSON.parse(JSON.stringify(message));
console.log(result);
<div id="googleForm">content</div>
If you pass a DOM element into JSON.stringify then you get a (JSON representation of an) empty object out.
DOM elements don't have any properties that will be automatically processed by JSON.stringify.
If you want to get data from a form, then you need to actually read the data from the form (e.g. get the input elements and read their value properties).
If you want to extract data from the DOM of a Google Form or if you want to send a postMessage from a Google Form then you need to write the JavaScript which does that in the HTML document containing the form.
You can't pull it across domains.
The page with the Google Form has access to the data and can push it across domains with post message.
Nothing you can do will let you just help yourself to that data.
It's private between the owner of the browser and the owner of the website and one of them needs to take explicit action if it is to be shared with anyone else (e.g. someone who has wrapped that website in an iframe).

implement post url in IFrame

How can I make a POST request to some URL (see my code below) in Javascript ?
My code so far doesn't work and I actually need to put it into an iFrame (having its with and height set to 0) to prevent the main page to reload.
$(document).ready(function(){
$("button").click(function(){
$.post(
"http://control.msg91.com/api/sendotp.php?otp_length=4&authkey=xxx&message=Your OTP is ##OTP##&sender=OTPSMS&mobile=xxx&otp_expiry=2"
, function(data){
alert(data);
});
});
});
If you want to use an iframe, then do not use XMLHttpRequest (NB $.post is a jQuery that wraps around XMLHttpRequest).
Create a <form>. Set its action to the URL. It's method to POST and its target to the ID of the <iframe>.
Put the data in that form. Then submit it.
If you want to do this entirely with JavaScript, then you can create the form using DOM and with entirely hidden inputs so that nothing shows up in the existing page. Ensure that you append the form to the document as some browsers will not let you submit forms that aren't part of the document.
That said, since you want an iframe with no dimensions, it seems odd to want to use an iframe at all.
You might be trying to work around CORS limitations, but you should be able to use the code you are using to make a request successfully. You just won't be able to tell if it was successful or not (because the restrictions are on reading the response). If you used an iframe, you would have the same limitations.
If you want to suppress the error message that is shown in the console, you could use fetch with mode: "no-cors". You still wouldn't be able to read the response though.
Make sure you are not hitting an issue with CORS. Unless the resource you are hitting allows exceptions to the cross-origin policy, you will not be able to access it if your webpage is not located on control.msg91.com.

How to send a request from JavaScript without base URL?

I'd like to send a request to a simple URL from my JavaScript, so that the base URL will NOT be added to the request URL. For example, the request should be sent to the following URL (without the base URL):
SAPEVENT:SOME_TEXT?2
I used the jQuery's $.ajax function in order to implement it, but without success.
Here is a JSFiddle for it:
http://jsfiddle.net/txb6tdjj/2/
The JS code:
function sendEvent(id) {
$.ajax("SAPEVENT:SOME_TEXT?" + id);
}
sendEvent(2);
I see the following error in the JS console:
XMLHttpRequest cannot load sapevent:SOME_TEXT?2. Cross origin requests
are only supported for HTTP. (jquery-2.1.0.js:8556)
I even set the parameter crossDomain: true, but it didn't help:
http://jsfiddle.net/auhx2v2v/3/
The JS code:
function sendEvent(id) {
$.ajax({
url: "SAPEVENT:SOME_TEXT?" + id,
crossDomain: true
});
}
sendEvent(2);
It ends up with the same error.
It works correct in the HTML like this:
http://jsfiddle.net/1f6npcn2/2/
The HTML code which works correctly:
<FORM action="SAPEVENT:PRESS_ME">
Click on me to send an event!
<INPUT TYPE="submit" VALUE="Press me to send an event!"/>
</FORM>
But I need to implement it in JavaScript, so that a request parameter can be set dynamically in the URL in JavaScript.
Do you know how to implement it in JS so that the request will be sent to the URL SAPEVENT:SOME_TEXT?2 without the base URL?
Additional information about used browsers: The error is shown only in Chrome. IE and Firefox do not show an error, but they also don't send the request.
Additional information for the SAP guys: I know there is a SAP Note 191908 which states that it's impossible, but a colleague has confirmed that he has successfully tested such functionality in an HTML page which used the same code as I copied above (see the HTML code above and http://jsfiddle.net/1f6npcn2/2/). So the SAP Note is wrong. I know how I can implement this functionality in HTML, but I don't know how I can implement it in JS. That's the problem.
I have no experience of working with SAP but I think you are missing a crucial part here.
In the samples you gave SAPEVENT:CLICK_ON_ME isn't a http url at all but rather it would invoke whatever handles the SAPEVENT-protocol on the local computer with the parameter CLICK_ON_ME. I'm guessing that you have some sort of client installed on your computer that does this for you (how do I create my own URL protocol? (e.g. so://...) contains some more information on how this is accomplished).
The reason your error-message talks about crossdomain-stuff is probably because it tried to interpret it as host:port.
So in other words, since this isn't a http url there isn't a webserver working on the other end so you can't do ajax-requests against it.
The SAPEVENT: stuff is not handled by any web server. The SAP GUI uses an embedded Internet Explorer and registers a custom protocol handler. There is no use in trying to use ajax techniques since you need to reach the container of the client, not the server. To reiterate: You do not want to "send a request" anywhere, you want to convince the browser that a certain local navigation event happened". SAP Note 191908 contains more information on that topic.
No idea about SAP Views, but to me this seems like a usual behaviour on webservers. I presume that SAPEVENT gets parsed by the server during the runtime to a more regular URI. Only the views get parsed, not the resources like CSS and JS, so the SAPEVENT placeholders in the JS file don't get parsed and the JS interpreter will not accept it as a valid URI. One of the common ways of solving this, is to create either a hidden form in the HTML or just a hidden input containing the server-generated values you are needing. For example
SAP View:
<input type="hidden" id="my_event_url" value="SAPEVENT:PRESS_ME">
JS:
function sendEvent(id) {
$.ajax({
url: $('#my_event_url').val() + '?' + id,
crossDomain: true
});
}
sendEvent(2);
I finally implemented it in JavaScript. Thanks go to this web page.
I modified the solution which was shown in this web page in order to add a link instead of a form in JavaScript.
This is the working solution in JS:
var targetUrl = "SAPEVENT:SOME_TEXT?2";
function sendSapEvent(targetUrl) {
var link = document.createElement("a");
link.setAttribute("style", "display:none;");
link.setAttribute("href", targetUrl);
// Move the click function to another variable
// so that it doesn't get overwritten.
link._click_function_ = link.click;
document.body.appendChild(link);
link._click_function_();
}
sendSapEvent(targetUrl);
You can find it also in this JSFiddle: http://jsfiddle.net/708r95p0/6/
It works! It sends a request to the URL sapevent:SOME_TEXT?2
I decided to use a link instead of a form element, bacause I couldn't pass the request parameter using a form.

Obtain the html source/text of another webage through JQuery

Is it possible to:
From within my webpage, get all the HTML source from another webpage. I need to do this in order to pass that other pages html source to my function.
The following different attempts don't work:
var html = $.get("http://simplyrecipes.com/recipes/braised_turkey_legs/").html();
var html = $.get("http://simplyrecipes.com/recipes/braised_turkey_legs/");
var html = $("http://simplyrecipes.com/recipes/braised_turkey_legs/").html();
Using Ajax, and get is just a shortcut for ajax, it's not really possible to get the source html from other domains, if that is what your trying to do? as ajax has a same origin policy for security reasons.
However going thru YQL it is possible to do is, read this to see how, or you could proxy with php or something else, with just regular get requests however it's not doable.
If the pages you are trying to get are on your domain, .load(); would probably be better.
Javascript has a same origin policy, this is what's holding you back.
jQuery's get function does not return the loaded data - rather, it calls a callback function and passes the data as a parameter.
This is from the documentation:
$.get('ajax/test.html', function(data) {
$('.result').html(data);
alert('Load was performed.');
});
P.S.: Note that in any case this will only work on the same domain, as cross-domain AJAX is normally not supported for security reasons.

Asynchronous cross-domain POST request via JavaScript?

I could just create a form and use that to do a POST request to any site, thing is the FORM method isn't asynchronous, I need to know when the page has finished loading. I tried messing around with this using an iframe with a form inside, but no success.
Any ideas?
EDIT
unfortunately I have no control over the response data, it varies from XML, json to simple text.
You can capture the onload event of an iframe. Target your form to the iframe and listen for the onload. You will not be able to access the contents of the iframe though, just the event.
Try something like this:
<iframe id='RS' name='RS' src='about:blank' onload='loaded()'></iframe>
<form action='wherever.php' target='RS' method='POST'>...</form>
script block:
var loadComplete = 0
function loaded() {
//avoid first onload
if(loadComplete==0) {
loadComplete=1
return()
}
alert("form has loaded")
}
IF you want to make cross domain requests you should either made a JSON call or use a serverside proxy. A serverside proxy is easy to set up, not sure why people avoid it so much. Set up rules in it so people can not use the proxy to request other things.
If the data returned from the cross domain post is JSON, then you can dynamically add a script tag pointing to the URI that returns the data. The browser will load that "script" which then you can access from other javascript.
YUI3's IO object offers cross-domain requests, however it does so using a small Flash control it embeds on the page.
While there is work going into secure cross-domain requests from JavaScript, at this time, you need to use a plugin like Flash or Silverlight as a bridge with which to make the request.
You can't do anything cross-domain using javascript. You'd have to use a backend language like PHP or asp or something.

Categories