Saving Javascript FormData() Object on client side - javascript

I have a html page which contains a form element with some text and file input elements.
This from is submitted with an ajax call to the server using a method suggested here: How can I upload files asynchronously?
As you may see in the referenced page from the above link, the FormData() object is used as a container for inputed data and I have done the job successfully.
But now we want to create a new page that have these html elements, save the text and file inputs on client side (Cookie or Local Strorage or . . .) and do the ajax submit later on another page.
I wasn`t able to save new FormData() in either cookie or local storage; what got saved is a small string:"[object FormData]" instead of entered file and strings.
I also tried using JSON.stringify() with no success; it just returned an empty JSON("{}").
(the code is using jQuery selector)
var postData = new FormData($(form)[0]);
// var sPostedData = JSON.stringify(postData); // returns: "{}"
var myStorage = window.localStorage; // returns: "[object FormData]"
myStorage.setItem("contentOrder", postData);
Please help, how should I save this object on my client-side?

To get the file from form data use formData.get('file') where file is the name of an input. The returned object will be of type Blob (see how to get its content).
The complete example can be found in this fiddle: https://jsfiddle.net/skm5m467/1/

Related

Not getting file data in Extjs Ajax request

I have a form on form-window, and inside form window I have a form with many fields and one upload button. When try to submit form using Ajax.request I have got textfield value but can not get file data. Except filename.
var fd = Ext.getCmp('users-form').form;
var fileInput = document.getElementById('company_logo');
console.log(fd.getEl().dom.files);
params = {
name : fd.findField('name').getValue(),
login : fd.findField('login').getValue(),
email : fd.findField('email').getValue(),
password : fd.findField('password').getValue(),
password_repeat : fd.findField('password_repeat').getValue(),
id : fd.findField('id').getValue()
company_logo : fd.findField('logo').getValue()
}
console.log(params);
Ext.Ajax.request({
url: Scada.reqUrl('users', 'save'),
method: 'post',
params: {
data: Ext.encode(params)
},
success: function() {
console.log('in success');
},
failure: function() {
console.log('in failure');
}
});
Here logo is input type file. I want to send logo data with ajax request. Please help me to figure out the problem. Thanks
Not sure why you started a new question instead of editing Encode form data while fileupload true in Extjs Form Submit as this seems to be the same problem.
Assuming logo is your file upload field you are trying to get the file data using getValue does not actually return the file content (if you use modern there is a getFiles method which returns the selected file objects).
General problems with your approach:
As I stated in my original answer it is not a good idea to send files in a standard ajax request. In your case those problems are:
If you expect getValue to return file contents, you are potentially encoding binary data into a JSON string. This will maybe work but create a large overhead and as the only available JSON datatype that could handle this content is string your parser would have to guess that property company_logo contains binary data and needs to be somehow converted into some sort of file reference.
You are sending files without metadata, so when just adding the raw content into your JSON string you would not be able to detect the expected file type without testing the file in multiple ways
As far as I know you would not be able to access the file content in classic toolkit at all
Submitting the data as a form: In your original question you explained that you submit the form instead of doing Ajax requests which is generally the preferred way.
When you submit a form that contains a file upload field the form will automatically be submitted as multipart/form-data the raw files are added to the request body with it's original content while preserving metadata collected by the browser.
If you look at https://docs.sencha.com/extjs/7.0.0/modern/Ext.Ajax.html#method-request you would have to set isUpload to true and use the form proeprty instead of params, passing a reference to the parent form.

Express JS render view with received image

I am working with two Express JS applications one is an API and second is application that is using this API by making requests and displaying received informations to user.
In API route I'm sending image as response:
router.get('/:customer_id',authController.isAuthenticated,(req,res) => {
.
. Retrieving customer data
.
return res.sendFile('/uploads/'+foundCustomer.doc_path);
});
And later another application is getting this document:
router.get('/:customer_id',(req,res) => {
var options = {
url: 'http://'+config.API.user+':'+config.API.password+'#'+config.API.host+':'+config.API.port+'/customers/'+req.params.customer_id
};
request(options,(err,response,body)=>{
return res.render('customer/show',{
document: ?, // Send document as parameter to view
});
});
});
In this point I want to render customer/show(EJS view engine) with customer document, but I don't want to save this document in my application files, because document is only needed to display in view (customer details and document are stored in another application).
I was trying to create temporary directory in my application structure, but it is difficult to manage deleting those not needed documents (Application has many users and at the same time many customers can be displayed).
Another solution that I was trying to implement is to make Ajax request on client side and latter append received document to <object data='document'>. But this request has to be authenticated with user and password, so I realised that storing credentials on client side javascript is not the best idea...
I am not sure that is it even possible to render and display image without saving in application files?
I would be grateful for any help, maybe the best workaround is to somehow manage temporarily saved documents.
Why not create a File object inside EJS template then use that for src attribute on an <img> ? You're already getting the raw buffer/blob from your image API server. Store it inside template.
From https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
// place this code (store this variable) inside of your EJS template
// so it can be used by the client-side JS
var aBlob = new Blob( array[, options]); // Where array is the raw buffer data returned from your image API server
See https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
var objectURL = URL.createObjectURL( aBlob ); // Where object is a Blob object
See https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject
const img = document.createElement('img');
img.src = objectURL;
Final solution (tested), using axios to make API request:
In my route I'm going to make HTTP request to my API to retrieve PDF file(document):
axios.get(`http://my-api/customer/id`).then(response => {
var photo = new Buffer(response.data, 'binary').toString('base64');
return res.render('customers/show',{
document: document
});
});
In my ejs view, I'm using HTML object tag to display received PDF:
<object data="data:application/pdf;base64,<%-document%>"></object>

$_REQUEST and $_FILES not populating on multipart/form-data

I have an ajax call bring up a form, this ajax call is successful using a string of variable var=value&var2=value2 etc. So i know that the AJAX Response is working.
Once the form is loaded into the AJAX Response it is parsed for any Javascript that needs to be run. I have an applet that I am building that modifies the form to upload four images.
$inRetailImages = "<script>ImgShower.init()</script>";
$inRetailImages .= "<div id=\"retailimagescontainer\"></div>";
This parse fine and loads the Javascript applet which is then used to load four images into it. When loading the four images, it modifies the form with an input for each image. I see this happening in the browsers debugger.
input = document.createElement('input');
input.id= "addShowerImage" + id;
input.name= 'addShowerImage' + id;
input.type='file';
input.size='40';
input.runat = 'server';
input.style.display = 'none';
input.accept='image/jpeg';
input.onchange = function(){ ImgShower.select(id); }
formparent.appendChild(input);
This appends the input to the current form. This is working, because when i submit the form without the images using a string rather than a form object, the form recognises the inputs although they are not valid images, when submitting the AJAX call via a string of vars, it takes the value of the local file directory, which is obviously not what is needed, but shows the AJAX call is working and the process script for the PHP is working. This form works perfectly when not uploading images.
if(isString(params)){
params = params + '&mode=' + mode;
contenttype = 'application/x-www-form-urlencoded';
}
else if (isObject(params)){
params.mode = mode;
queryparams = Request.getQueryParamsAsObject(params.params);
Objects.merge(params, queryparams);
delete params["params"];
var formParams = new FormData();
for (key in params) {
formParams.append(key, params[key]);
log("error", "FormData Key: " + key + " Data:" + params[key]);
}
params = formParams;
//contenttype = "multipart/form-data;Charset=UTF-8;boundary=xxxxx;";
//contenttype = 'application/x-www-form-urlencoded';
EDIT: I CHANGED THE CONTENT TYPE TO FALSE
contenttype = false;
AND PUT AN IF STATEMENT TO PUT NO HEADER IN THE AJAX SEND
AND EDITED
formParams.append(key, params[key] || "");
SO THAT THE PASSED VALUES WERE NOT EMPTY AND THE FORM SENDS
IT STILL WONT PASS AN IMAGE FILE TO $_FILES BUT THIS MADE IT FILL $_REQUEST
}
I have a script that takes all the value from the form and turns it into an Object Array. In the debugger i can see all the values from the form as expected including the FileItem for each of the four images. When view the log from the script above loading it into the formData object, i can see the valid entries and they all look good.
I have tried multiple content types, i have tried sending just the object without the form data, i have tried adding a new form wrapper to the form data, i have tried naming a new form wrapper for the formData object, i have looked through my PHP settings, and gone through this list.
Why would $_FILES be empty when uploading files to PHP?
The list of to watch out for is pretty extensive and my php.ini settings seem fine.
When i submit the form using application/x-www-form-urlencoded i see a large multipart in the response, but it does not populate $_REQUEST, $_POST or $_FILES as one would excpect. It loads the $_REQUEST with one variable and the multipart data.
When i submit the form using multipart/form-data, i see the Response in Googles Network Tab as a Payload being sent to the PHP Server, but at the PHP end it does not populate $_REQUEST, $_POST or $_FILES at all.
This is what i see in the Payload of the Request and Response on Google Chromes Network Tab of the Developer Tools.
------WebKitFormBoundaryp39DDe2JV8jjxA5j
Content-Disposition: form-data; name="addRetailName"
asdasd
------WebKitFormBoundaryp39DDe2JV8jjxA5j
Content-Disposition: form-data; name="addRetailCode"
TEST001
------WebKitFormBoundaryp39DDe2JV8jjxA5j
Content-Disposition: form-data; name="addRetailManuf"
etc for 34 fields
This form has 34 fields, + the 4 added fields using the javascript to update the form. These images can be seen in the Payload as well.
------WebKitFormBoundaryzmu5mDvaLNnvsolE
Content-Disposition: form-data; name="addShowerImage1"
[object FileList]
Why does this not populate the $_REQUEST and $_FILES arrays. I output the arrays in the PHP using print_r($_REQUEST) or print_r($_FILES) and get array() as the response.
I am not getting any files coming through, nor am i getting any form data coming through at all. Yet i see the multipart being sent in the Payload of the Request.
I am using pure javascript with no libraries and no jscript. I prefer to write in pure javascript.
I should also state, that i am on a windows 7 ultimate machine using IIS 7 and PHP 5.4. via FastCGI.
When calling the ajax, the form is passed and collected by a request function. This function scrolls through all the items of the form and collects their values or contents. This works for all text based content.
I call all file inputs
var inputs = formObj.getElementsByTagName("input");
then traverse through those inputs
case "file":
values[input_name] = inputs[i].files;
break;
return values;
I even tried
values[input_name] = inputs[i].files[0]; returns File and not FileList
and i get this in the Payload
------WebKitFormBoundaryqsinSx1UoPEKAYOD
Content-Disposition: form-data; name="addShowerImage1";
filename="13006682_10208925038300663_5601989752145619827_n.jpg"
Content-Type: image/jpeg
This is then an Object Array
values{var1: value1, filevar: File}
It seems the FileList/File is appearing here. This is at the very beginning of recieving the form submit, the function traversing all the form values sees the files>fileList. I dont see anything other than fileList.

How to send an Array via URL and extract it in PHP?

Here is a script.
It provides some select inputs which allow picking from various types of options. When the submit button is pressed it records the data in mats and pushes the mats array into an array called materialsUsed. Everytime the submit button is clicked a new array is added in materialsUsed.
I want to know how to send the materialsUsed array through a URL to php to extract the data there and insert it into an array created in PHP.
var mats = [name= "", thick= "", size= "", quantity= 0, price= 0];
mats.name = document.getElementById("mat").options[document.getElementById("mat").selectedIndex].value;
mats.thick = document.getElementById("thick").options[document.getElementById("thick").selectedIndex].value;
mats.size = document.getElementById("size").options[document.getElementById("size").selectedIndex].value;
mats.price = parseFloat($('#priceto').val()).toFixed(2);
mats.quantity = parseInt($('#quant').val());
materialsUsed.push(mats);
If you would like to simply load them as GET values into the URL just set them directly in the URL using location.href. Then simply use $__GET (IE: $__GET['mat']) in PHP to grab values.
var baseURL = "http://yourdomain.com";
window.location.href = baseURL + "?mat=" + mats.name + "&thick=" + mats.thick etc...
First you have to properly prepare your mats array and convert materialsUsed array into JSON format. Then you can call an ajax function like below, to send it to the php script.
var jsonString = JSON.stringify(materialsUsed);
$.ajax({
type: "GET",
url: "your_script.php",
data: {data : jsonString},
success: function(){
alert("Successfully sent the data!");
}
});
From the your_script.php file, you can perform this to extract the array.
$data = json_decode(stripslashes($_GET['data']));
Important
When using GET method, the amount of the data (length of url) is
limited. So, if your materialUsed array is too huge, you should use
POST method instead.
I think what you're looking for is making an ajax call to your php script providing your js array as its data.
You should listen for the form submission event in your javascript and launch an AJAX call to your PHP script providing your array. You may send your array via the URL (query string) using a GET or in the request body using a POST (that's an option you specify in your AJAX call). Then you would just retrieve your array in your php script an do whatever you want with it.
I suggest you read more on form submission events and AJAX calls in javaScript.
Quick hint : if you have the possibility to do so, try using jQuery as AJAX is way easier to use with jQuery.
You are trying to use associative array, but it's not possible in Javascript as far as I know.
I'd say the best way to do that is creating a object, parsing to json and sending to php. Does't look that hard.

Passing JSON to the server like GET/POST to get a file instead of ajax reply

I've an object created in javacript with a lot of data and I serialize it to JSON to send it to the server. After this, the server must do somework and create a dynamic file, so it can be downloaded.
For the last routine I created an ASHX but can be modified. Already I'm getting a "httpcontext" that I found in another question how to work with it to get the data from the JSON, so my question is not related about this.
The problem (more oriented to JS) is this one:
How can I sent the JSON to the ASHX as a URL/GET/POST to the generic handler to avoid the "ajax reply" and be the user open a new window with the link dinamically generated?
Thanks, sorry for my english (please edit) and kind regards!
Note 1: I can't use third-part code
Note 2: I can't use JSON.NET
Note 3: I can't save the report on the server so the response must be a generated file to download, even more, the download itself is the response of the server.
---UPDATE----
I've been read this question:
Can I post JSON without using AJAX?
The only thing I don't understand from that question is how to make it work, thinking in that I've a "link" to download
I assume you do not want to refresh the whole page so there is a workaround.
1) Ajax-load an iframe which is a separate aspx file for example.
2) In the codebehind of that separate aspx file, generate the file in memory and convert it to an array of bytes.
3) Then use Response to stream the bytes to the user.
Finally I resolved the issue with this (in the right way).
I just take my json object and send it trough POST with a dynamic form generated with javfascript
var dataToPostInExport = JSON.stringify(queryToVerify);
//Convert To POST and send
var VerifyForm = document.createElement("form");
VerifyForm.target = "_blank";
VerifyForm.method = "POST";
VerifyForm.action = "file.ashx";
var dataInput = document.createElement("input");
dataInput.type = "hidden";
dataInput.name = "mydata";
dataInput.value = dataToPostInExport;
VerifyForm.appendChild(dataInput);
document.body.appendChild(VerifyForm);
VerifyForm.submit();
Then in the ashx file:
Dim DataToParse As String
DataToParse = HttpContext.Current.Request.Form("mydata")
Dim JSSerializer As New JavaScriptSerializer
Dim QueryToExport as my very own type!
QueryToExport = JSSerializer.Deserialize(Of My Own Type)(dataToParse)

Categories