How to add custom properties to file form javascript / jquery - javascript

I'm aiming to send fileform with images and additional information like height and width. I can't figure out how to add some custom props to file form object.
$("#saveImg").on('click', function () {
var formData = new FormData(),
allFiles = [];
$('input[name=fileUpload]').each(function (index) {
if (inputFileValidation(this)) {
(function (files) {
if (files.length != 0) { allFiles.push(files[0]); }
})(this.files)
}
});
for (var i = 0; i != allFiles.length; i++) {
var img = new Image()
img.src = window.URL.createObjectURL(allFiles[i]);
$(img).on('load', function () {
formData.append("files_h", img.naturalHeight);
formData.append("files_w", img.naturalWidth);
formData.append("files", allFiles[i]);
window.URL.revokeObjectURL(allFiles[i]);
});
}
$.ajax({
url: '#Url.Action("Upload", "Image")',
data: formData,
processData: false,
contentType: false,
type: "POST",
success: function () {}
errors: function () {}
});
});
[HttpPost]
public async Task<IActionResult> Upload (IList<IFormFile> files)
{
//do something ;
}
I also tried:
[HttpPost]
public async Task<IActionResult> Upload (IList<IFormFile> files, IList<IFormFile> files_h, IList<IFormFile> files_w)
{
//do something ;
}
Maybe you have another idea how to send image with additional data? I tried to convert file form and additional info to JSON by that didn't work.
Edit
Thank you all for your suggestion, they are really important to me because I will definitely use them in the future.
However, in this project I have already given up using the file reader due to its asynchrony and having fun with promise. The aim is simple and less javascript and more c#
I apologize for misleading you in the title javascript andjquery - and I mark the answer related to c #. I did this because this answer is related to my next task because the CoreCompat.System.Drawing library is undoubtedly still useful for editing photos in the future.
Thanks!!

If you want to get the Width and Height properties while uploading images in ASP.NET Core. I suggest you to install this package: CoreCompat.System.Drawing
Install-Package CoreCompat.System.Drawing -Version 1.0.0-beta006
In the server, after saving your files to the specific path. You could use System.Drawing.Image class to get the Width and Height properties:
using (var image = System.Drawing.Image.FromFile(filePath))
{
int width = image.Width;
int height = image.Height;
}
You don't have to add files_h and files_w properties to your client model before sending to server.
And then, by using this way, I've edited your js code to:
$("#saveImg").on('click', function () {
var formData = new FormData();
for (var input of Array.from($('input[name=fileUpload]')))
{
if (inputFileValidation(input) && input.files.length) {
formData.append('files', input.files[0]);
}
}
$.ajax({
url: '#Url.Action("Upload", "Image")',
data: formData,
processData: false,
contentType: false,
type: "POST",
success: function () {}
errors: function () {}
});
});

This is one approach; taken from there:
$('#btnUpload').click(function () {
// Checking whether FormData is available in browser
if (window.FormData !== undefined) {
var fileUpload = $("#FileUpload1").get(0);
var files = fileUpload.files;
// Create FormData object
var fileData = new FormData();
// Looping over all files and add it to FormData object
for (var i = 0; i < files.length; i++) {
fileData.append(files[i].name, files[i]);
}
// Adding one more key to FormData object
fileData.append('username', ‘Manas’);
$.ajax({
url: '/Home/UploadFiles',
type: "POST",
contentType: false, // Not to set any content header
processData: false, // Not to process data
data: fileData,
success: function (result) {
alert(result);
},
error: function (err) {
alert(err.statusText);
}
});
} else {
alert("FormData is not supported.");
}
});
Another approach is to use the FileReader class to read the uploaded file, convert it to a base 64 string. Then you can send the base 64 string to the server.

Related

JavaScript "Out of Memory" Error with FileReader in a for loop

I have a function where I should read up to 300 files (JSON each one with aprox. 20MB) and send it over a node.js server to a influxdb.
My problem now is that when I execute my code with 15-25 files everything is working fine but when I select 200 or more I get really quick a "Out of Memory" exception from the browser.
I think that it is the "new FileReader" inside of the for loop but when I move it outside it won't work anything.
so here is my code:
for (var i = 0; i < fileList.length; i++) {
//console.log("a---------------------------");
let reader = new FileReader();
reader.onload = await onReaderLoad;
reader.readAsText(fileList[i]);
let tempData = "";
async function onReaderLoad(event) {
//console.log("b------");
//data1 = JSON.parse(event.target.result);
tempData = event.target.result; //send as text is much faster to the server as as parsed JSON
//console.log("c------");
await writeTheData(tempData);
//console.log("d------");
}
}
and here the code of the "writeTheData" function which is above the other code in the .js file
function writeTheData(tempData) {
return $.ajax({
url: "http://localhost:7000/api/writeJSONtoInfluxDB",
type: "POST",
contentType: "application/json",
data: tempData,
success: function (data) {
console.warn("uploading and import data: " + data);
},
}).then((response) => response.data);
}
any ideas how to fix this?

Knockout - Upload all files one after another using a single button

Since I'm comparatively new to Knockout.js, which would be the best approach in Knockout to upload all files one after the other using a single button?
Currently, the user has to click on individual Upload button to upload one or more files to an azure container. See FileModel below.
An enhancement to this feature is to allow user to upload all files at once
using Upload All Files button. See PageModel below.
What I have tried so far is to iterate through each file object in the Files = ko.observableArray() and upload it using its individual AJAX but that would defeat the purpose of using an AJAX call.
PageModel
var PageModel = function (r) {
var self = this;
this.Files = ko.observableArray();
this.UploadAllFiles = function (e) {
// Don't want to use this, because AJAX!
ko.utils.arrayForEach(self.Files(), function (file) {
file.UploadFile();
});
}
}
FileModel
var FileModel = function (r, fileObject) {
var self = this;
this.FileObject = fileObject;
this.Name = r.name;
this.Comment = ko.observable("");
this.UploadFile = function () {
var formData = new FormData();
formData.append('File', fileObject);
formData.append('Comment', self.Comment());
$.ajax({
url: '/Controller/Action',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function (data) {
},
error: function (data) {
}
});
}
}
window.model = new PageModel();
ko.applyBindings(model);
PS: There is also a manually entered string associated with every file using data-bind="textInput : Comment". This additional information is also passed through with the file object in the AJAX call.

TypeError: Illegal invocationType when passing file through ajax

My goal is to pass a file to my backend which runs on laravel. The file is drag and dropped on the web page and not my input file. I went through the previous issues on stack overflow and fixed my code accordingly but still the issue exists.
Here is my javascript code that uses ajax to pass the file
$("html").on("drop", function (e) {
e.preventDefault();
e.stopPropagation();
var dt = e.dataTransfer || (e.originalEvent && e.originalEvent.dataTransfer);
var files = e.target.files || (dt && dt.files);
if (files) {
for (var i = 0; i < e.originalEvent.dataTransfer.files.length; i++) {
var file_ext = e.originalEvent.dataTransfer.files[i].name.split('.').pop();
console.log(file_ext);
if ((file_ext == 'pdf') || (file_ext == 'docx') || (file_ext == 'txt')) {
console.log('right file');
var resume = e.originalEvent.dataTransfer.files[i].value;
var form_data = new FormData();
form_data.append("resume", resume);
var resume_val = e.originalEvent.dataTransfer.files[i].name;
console.log(form_data);
var token = $('#token').val()
var hello = "hello";
$.ajax({
url: '/resume_upload',
type: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: ({
resume: form_data,
wish: "Naveen its working"
}),
success: function (data) {
console.log(data.msg);
alert(data.msg);
},
error: function (xhr, status, error) {
console.log(error);
alert(error)
}
});
} else {
console.log('wrong file');
}
}
} else {
console.log('file not recieved');
}
});
Here is where i get the file
var resume = e.originalEvent.dataTransfer.files[i].value;
var form_data = new FormData();
form_data.append("resume",resume);
But when i console.log(form_data) it logged FormData{} just empty form data. So obviously i pass nothing with my ajax function. Am i doing anything wrong in getting the file ? I don't have an idea how to go about this.
Maybe I misunderstood what do you want but I think you should do stg like this:
var form_data = new FormData();
form_data.append('resume_file_name', e.originalEvent.dataTransfer.files[i].value);
form_data.append('resume_file', e.originalEvent.dataTransfer.files[i]);
form_data.append('wish', "Naveen its working");
if u want to upload the file, not just some file info
and with FormData, you can pass all the data you want, so just pass this to $.ajax data parameter:
data: form_data,
and there is something else, may this was the original problem:
when jQuery handles the parameters it also tries to convert it, but this causes problems, when pass a FormData type to data attribute, so you should also add these parameters to the $.ajax input object:
processData: false,
contentType: false
parameters.
Sorry for my bad english!

I'm submitting the form through ajax using jquery serialization function

var values = $('#form_field').serialize();
dataS = "val="+values;
$.ajax({
type: "POST",
url: URL,
data: dataS,
cache: false,
dataType: 'json',
success: function(response)
{ },
});
But the form has an (<input type="file"> field) how do I pass the file into the form using this ajax serialization method. When I print $_FILES doesn't getting any output.
You can't past the $_FILES variable when using ajax. I can assure you that. Thanks.
Ajax does not support file uploads, you should use iframe instead.
you can check further detail here
Posting via Ajax file upload isn't straight forward. First, it isn't directly doable using XHR1.
There are two main ways to do the uploads, using a frame and using the XHR2 spec and the FormData object. This is the method I would recommend.
The easiest way to do this is then to perform two uploads. I'm going to borrow some code here, from GitHub user optikalefx to show you how to do it using jQuery:
// Ajax File upload with jQuery and XHR2
// Sean Clark http://square-bracket.com
// xhr2 file upload
// data is optional
$.fn.upload = function(remote,data,successFn,progressFn) {
// if we dont have post data, move it along
if(typeof data != "object") {
progressFn = successFn;
successFn = data;
}
return this.each(function() {
if($(this)[0].files[0]) {
var formData = new FormData();
formData.append($(this).attr("name"), $(this)[0].files[0]);
// if we have post data too
if(typeof data == "object") {
for(var i in data) {
formData.append(i,data[i]);
}
}
// do the ajax request
$.ajax({
url: remote,
type: 'POST',
xhr: function() {
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload && progressFn){
myXhr.upload.addEventListener('progress',function(prog) {
var value = ~~((prog.loaded / prog.total) * 100);
// if we passed a progress function
if(progressFn && typeof progressFn == "function") {
progressFn(prog,value);
// if we passed a progress element
} else if (progressFn) {
$(progressFn).val(value);
}
}, false);
}
return myXhr;
},
data: formData,
dataType: "json",
cache: false,
contentType: false,
processData: false,
complete : function(res) {
var json;
try {
json = JSON.parse(res.responseText);
} catch(e) {
json = res.responseText;
}
if(successFn) successFn(json);
}
});
}
});
};
I should also note that browser support for this is a little more limited, despite XHR2 being around for 2 years now: https://developer.mozilla.org/en-US/docs/Web/API/FormData contains more information as well as a Browser compatibility chart.

Catching ajax file in ASP.Net MVC Controller

I want to upload file using ajax to an ASP.Net MVC Controller
My JavaScript code looks like this, basically every time the user changed the input value, it will automatically upload the file to the controller
var formdata = false;
if (window.FormData) {
formdata = new FormData();
}
$('input[name=default_export_filename]').change(function() {
var i = 0, len = this.files.length, img, reader, file;
for ( ; i < len; i++ ) {
file = this.files[i];
if (file.type.match(/spreadsheet/) || file.type.match(/ms-excel/)) {
if ( window.FileReader ) {
reader = new FileReader();
reader.onloadend = function (e) {
//showUploadedItem(e.target.result, file.fileName);
};
reader.readAsDataURL(file);
}
if (formdata) {
formdata.append("default_export_filename", file);
}
}
}
if (formdata) {
$.ajax({
url: root + mod + '/uploaddef',
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function (res) {
console.log(res);
}
});
}
});
In the controller side, I couldn't catch that file using this
[HttpPost]
public ActionResult UploadDEF(HttpPostedFileBase file)
{
var jsonData = new
{
response = 3
};
return Json(jsonData); ;
}
Or this
[HttpPost]
public ActionResult UploadDEF(FormCollectionfile)
{
var jsonData = new
{
response = 3
};
return Json(jsonData); ;
}
The file argument is always null. But in the firebug, I can see that the browser is posting the file to the server. With what object should I catch the file?
I realize the FormData object is not supported in older browser, but my clients are all using the latest browser. So that is not a problem.
The problem is solved.
It turns out I don't have to give any parameters to the controller's method. The files are available through Request object.
Thanks all
You can't use ajax POST to upload a file like this, must be a form submit.
Have a look at component like AjaxUploadify or similar.

Categories

Resources