Hit an interesting problem today when trying to upload an image file < 2MB using dojo.io.iframe.
My function to process the form is called, but before the form is posted to the server I am getting the following error:
TypeError: ifd.getElementsByTagName("textarea")[0] is undefined
My function that is used to action the post of the form is :
function uploadnewlogo(){
var logoDiv = dojo.byId('userlogo');
var logoMsg = dojo.byId('uploadmesg');
//prep the io frame to send logo data.
dojo.io.iframe.send({
url: "/users/profile/changelogo/",
method: "post",
handleAs: "text",
form: dojo.byId('logoUploadFrm'),
handle: function(data,ioArgs){
var response = dojo.fromJson(data);
if(response.status == 'success'){
//first clear the image
//dojo.style(logoDiv, "display", "none");
logoDiv.innerHTML = "";
//then we update the image
logoDiv.innerHTML = response.image;
}else if(response.status == 'error'){
logoMsg.innerHTML = data.mesg;
}else{
logoMsg.innerHTML = '<div class="error">Whoops! We can not process your image.</div>';
}
},
error: function(data, ioArgs){
logoMsg.innerHTML = '<div class="error">' + data + '</div>';
}
});
}
The form is very basic with just a File input component and a simple button that calls this bit of javascript and dojo.
I've got very similar code in my application that uploads word/pdf documents and that doesn't error, but for some reason this does.
Any ideas or pointers on what I should try to get this to work without errors?
Oh I'm using php and Zend framework for the backend if that has anything to do with it, but I doubt it as it's not even hitting the server before it fails.
Many thanks,
Grant
Another common reason for this error is the server isn't packaging the data correctly. This means even if you have set "handleAs: json" you have to send that json wrapped in some html. This is what it should look like:
<html>
<body>
<textarea>
{ payload: "my json payload here" }
</textarea>
</body>
</html>
Your error was saying it couldn't find the textarea in your return from the server. For more look at http://docs.dojocampus.org/dojo/io/iframe
Since the load handler of dojo.io.iframe.send() has been triggered, the request should have been sent to the server and response is back. I think the response from server is not correct. Maybe the server returns an error page.
Use Firebug to inspect current page's DOM and find the transporting iframe created by Dojo and check its content. Firebug can capture iframe I/O too, check its Net tab. You may find the root cause of this issue.
Did you respect the constraint written in the doc ?
IMPORTANT: For all values EXCEPT html and xml, The server response should be an HTML file with a textarea element. The response data should be inside the textarea element. Using an HTML document is the only reliable, cross-browser way this transport can know when the response has loaded. For the text/html (Or XML) mimetype, just return a normal HTML/XML document. In other words, your services for JSON and Text formats should return the data wrapped as the following:
Related
I am trying to build a firefox addon where the user fills out a form and submits it to a server. I would like to know how to access the response back from the server. In this example the response is ["SUCCESS", "createAccount"]
I see the data in this little popup that appears after I click submit, in the Raw Data tab. (see picture).
I just don't know how to access that from my code. This seems like it should be simple but I cannot figure it out.
I have tried overriding the onsubmit and onclick methods/listeners to route them through an ajax/XMLHttpRequest, but I get a content security error (Content Security Policy: The page’s settings blocked the loading of a resource at self (“script-src”). Source: onclick attribute on BUTTON element.)
I have looked at other SO posts, none of them are specifically for responses from forms in an addon.
Any help is appreciated.
The answer is to use webRequests.filterResponseData.
The code goes something like this:
var rawdata;
var listener = function(result){
let filter = chrome.webRequest.filterResponseData(result.requestId); //https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/filterResponseData
filter.ondata = event => {
self.data = {
data: Array.apply(null, new Uint8Array(event.data)),
contentType: result.type
};
rawdata = arrayBufferToData.toJSON(event.data);
}
filter.onstop = event => {
filter.disconnect();
}
}
browser.webRequest.onHeadersReceived.addListener(listener, {urls: ["<all_urls>"]},["blocking"]);
rawdata will then have the correct values.
Thanks to icecub for pointing the right way.
arrayBufferToData comes from here
Unfortunately this only works for firefox, not chrome.
I have a file to download using jquery which I achieve by window.location.href. But my challenge is that I need to find out whether the file which I intend to download is empty or not. If its empty, I need to show a popup showing error message, instead of downloading that empty file. But I don't know how to catch the file is empty or not before download using jquery.
I searched in net and I couldn't find an answer. Please help me to solve this issue.
To achieve this you can send a HEAD request to the URL to get the headers of the response. Then you can check the Content-Length value, something like this:
$.ajax('/yourfile.foo', {
type: 'HEAD',
success: function(data, status, xhr) {
var size = parseInt(xhr.getResponseHeader('Content-Length'), 10) || 0;
if (size != 0) {
window.location.assign('/yourfile.foo');
} else {
console.log('invalid file, show an error here...');
}
}
});
This being said, prevention is a much better solution to this problem. You should amend your logic so that invalid files are not even displayed to the user. Allowing users to have the option to even select things they cannot have will just infuriate them.
I am working in Spring 3, Java, JSP, javascript, and jquery, using Ajax occasionally. I have server functions that generate a PDF; I have a new requirement to show a "preview" of a PDF document.
I have code that generates the PDF document, that works fine. I can show it by hacking my source to display it in the place we normally show the un-watermarked completed document, so I know the generation of the PDF is working.
What I now want to do is display that PDF in its own tab as the result of clicking on a button (or link) on our web page. There are a few restrictions:
I have a bunch of data to pass up to the controller from the web page, data that it needs to generate the PDF. We have code that does this through a POST method, and use Ajax to post the necessary data.
It would be inconvenient for the PDF to show up in the same window as the button clicked to show the PDF; a popup asking if the user wants to download or view elsewhere is fine. The users aren't sophisticated enough to depend on theiri knowledge of the 'back' button here. So we want the PDF to show up elsewhere, preferably on another tab in the window but another entire window would be ok.
I have the following in my controller at the moment:
response.setContentLength(pdfGenerated.length);
response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setHeader("Content-Disposition", "attachment;filename=\"Preview.pdf\"");
ServletOutputStream out = response.getOutputStream();
out.write(pdfGenerated); // (encodedPdf);
out.flush();
out.close();
The ajax call looks like this:
$("#generatePDFPreview").live("click", function() {
var gridData = getCorrectedGridData();
var valid = validateContractContent(gridData);
if (valid) {
// the call below saves the contract data and then generates its PDF
$.ajax({
url: getModelObject("generatePDFPreviewURL")
,type:'POST'
,data: {'editedContents':JSON.stringify(gridData)}
,datatype: "application/pdf"
,async: false
,success: function(data) {
if(data != null && data.length>0 && data != "Error") {
//data must be contract id...use it to build the complete URL.
//window.location.href = getModelObject("deliveryScreenURL") + data;
window.open("data:application/pdf;base64, " + data);
} else {
alert("PDF preview not generated...Data returned is not ok. Please try again or contact Sales Support.");
}
}
});
}
});
I have tried different things here; I have left off the 'success' function entirely; I have tried encoding the data (base64) and returning that, and using data:application/pdf, etc., but that failed -- I have some evidence that the PDF data was too long for this, but am not sure (it was 85k-90k, the URL string stopped at something like 32784).
I am not worried about whether my user has the PDF reader installed. They must have it installed to use this and other parts of the application.
It is frustrating to be so close; all evidence is that we have most of the pieces in place, it's should just be a matter of telling the browser that we want it to use the PDF Reader to handle these bytes.
Can someone point us to a method, or point out what's wrong with what we've got now?
I am using AJAX calls and getting JSON as response then it is used to perform various operations. However there are times when I will get HTML response instead of AJAX(a full HTML page), in such cases I want to reload the page with the HTML content (as if a redirection happened). I am able to find out whether a response is HTML or JSON, however I am unable to find a way in which I can reload the page with HTML content received as part of response so that user only sees the HTML content received as part of AJAX response.
Here is the code:
function redirectIfHTML(xhr,data){
var ct = xhr.getResponseHeader("content-type") || "";
if (ct.indexOf('html') > -1) {
// Need to reload the data on current window
}
}
You can nuke and rewrite the entire content of the page using document.write():
document.write("<html><body><p>Hello world!</p></body></html>");
If you want to keep the <head> (and therefore your CSS and so forth) a cleaner solution is to replace the content of the body:
$('body').html("<p>Hello world!</p>");
I would never want to do something like this, but you can use some data-url to solve:
A data-URI with MIME-type text/html + the html you just received:
var myurl = 'data:text/html,' + <HTML HERE>
Then you do:
document.location.href = myurl
(i didn't really try it)
This is similar to: How to open a file using JavaScript?
Goal: to retrieve/open a file on an image's double click
function getFile(filename){
// setting mime this way is for example only
var mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
jQuery.ajax({ url : 'get_file.pl',
data : {filename:filename},
success : function(data){
var win = window.open('','title');
win.document.open(mime);
win.document.write(data);
win.document.close();
}
});
}
jQuery('#imgID').dblclick(function(){
getFile('someFile.docx');
});
I'm doing this off the top of my head, but I think the above would work for text files, but not binary. Is there a plugin that does this properly? The ideal would be to open the file in the browser (or application), rather than download, but I doubt that is a dream. If the file must be downloaded with the save/open dialog, that's fine.
Edit:
One piece of information that I forgot to mention is that I'd like this to be a POST request. This is partly why I was looking at AJAX to begin with. I've seen workarounds that have created forms/iframes to do something similar, but I was looking for a better handler of the returned info.
Seems to me there's no reason to do this via AJAX. Just open the new window to get_file.pl?filename=... and let the browser handle it. If the user has a plugin capable of handling the Content-Type sent by get_file.pl, the file will display; otherwise, it should download like any other file.
function getFile(filename) {
window.open('get_file.pl?filename=' + filename,'title');
}
jQuery('#imgID').dblclick(function() {
getFile('someFile.docx');
});
Edit: If you want to POST to your script, you can do it with some <form> hackery:
function getFile(filename) {
var win = 'w' + Math.floor(Math.random() * 10000000000000);
window.open('', win,'width=250,height=100');
var f = $('<form></form>')
.attr({target: win, method:'post', action: 'get_file.pl'})
.appendTo(document.body);
var i = $('<input>')
.attr({type:'hidden',name:'filename',value:filename})
.appendTo(f);
f[0].submit();
f.remove();
}
Of course, this is somewhat silly since it is impossible to hide your data from "prying eyes" with developer tools. If your filename really is sensitive, issue access tokens to the client, and look up the data in your sever script.