I'm trying to upload a file and the form data using ajax. But I'm getting a formData object with null values.
I can log the fileUpload object corretly but my formData log is empty.
Can someone explain me what's wrong?
$(document).ready(function () {
var formData = new FormData();
$('#fileUpload').change(function () {
formData.append('file',$('#fileUpload')[0].files[0]);
console.log($('#fileUpload')[0].files[0]);
});
$('#btnSubmit').click(function (e) {
e.preventDefault();
formData.append('data',$('#creationForm')[0]);
console.log(formData);
$.ajax({
type: 'post',
url: '/upload/testCase',
data: formData,
processData: false,
success: function (result) {},
error: function () {}
});
return false;
});
});
And I want to use them in Spring Controller.
#RequestMapping(value = "/upload/testCase" , method = RequestMethod.POST)
public #ResponseBody String uploadTestCase(#RequestParam("data") String data, #RequestParam("file") MultipartFile file ) {
//TestCases.upload(file);
System.out.println(data + file);
return "";
}
formData is not null, you are just not inspecting it correctly:
Try this:
$('#fileUpload').change(function () {
formData.append('uploadedFile',$('#fileUpload')[0].files[0]);
// inspect each key/value entry
for (var data of formData.entries()) {
console.log(data[0] + ', ' + data[1]);
}
});
Related
I have an Input tag like this:
<input type="file" name="file" accept="image/png, image/jpeg" class="choose">
<button id="bAddImage" type="button"> AddImage </button>
After the user clicks the bAddImage button, if the user has selected a file, this file will be saved in an Array List in jQuery as follows:
$('body').on('click',
'#bAddImage',
function(event) {
event.preventDefault();
if ($('.choose')[0].files[0] == null) {
return;
}
IMAGES.push({
File: $('.choose')[0].files[0],
});
});
The problem I have here are the files in this list. These files will not be sent to the server after calling the method.
Class C#
public class AddProductRequest
{
public string ProductNameEn { get; set; }
public List<HttpPostedFileBase> ProductImages { get; set; }
}
Call Method in JavaScript
$('body').on('click',
'#bSubmit',
function(event) {
event.preventDefault();
var images = [];
if (IMAGES.length > 0) {
$.each(IMAGES,
function (index, item) {
images.push({
item.File
});
});
}
const formData = JSON.stringify({
ProductNameEn: 'test',
ProductImages: images *\\not send value*
});
$.ajax({
type: "POST",
url: '#Url.Action("AdminApiAddProduct", "CallApi", new {area = "AdminArea"})',
contentType: "application/json",
dataType: "json",
data: formData,
success: function (response) {
},
error: function () {
}
});
});
formData in console.log
{"ProductNameEn":"test","ProductImages":["{}"]}
Sends ProductImages is null while images have a value.
images in console.log
(1) […]
0: File { name: "test.png", lastModified: 1599110560934, size: 98288, … }
length: 1
: Array []
script:1:151
Method in C#
[HttpPost]
public ActionResult AdminApiAddProduct(AddProductRequest request)
{
var nameEn = request.ProductNameEn; //test
if ((request.ProductImages ?? new List<HttpPostedFileBase>()).Count > 0)
{
**//Problem is NULL**
}
}
The whole problem I have is that the files selected by the user are not sent to the server and the value is ProductImages = null.
You must use FormData instead of JSON and append you Image one by one with other data to it, I have modified your code
$(function () {
var formData = new FormData();
$('body').on('click',
'#bAddImage',
function (event) {
event.preventDefault();
if ($('.choose')[0].files[0] == null) {
return;
}
formData.append($(".choose")[0].files[0].name, $(".choose")[0].files[0]);
});
$("body").on("click", "#bSubmit", function (e) {
e.preventDefault();
$.ajax({
url: '/api/CallApi/AdminApiAddProduct',
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
success: function (fileName) {
// success code
},
error: function (error) {
console.log(error);
}
});
});
in your action get files using HttpContext.Current.Request.Files
[HttpPost]
[Route("api/CallApi/AdminApiAddProduct")]
public IHttpActionResult AdminApiAddProduct()
{
try
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs(filePath);
}
return Ok("files uploaded!");
}
return Ok("no files to upload!");
}
catch (Exception ex)
{
throw ex;
}
}
I'm trying to implement file download functionality thru ajax call in MVC.
After calling of controller method i always have a "parseerror", can somebody explain me why?
my ajax:
tab.on("click", ".FileDownload", function (e) {
//$('#uploadStatus').html("ok");
var tr = $(this).closest("tr");
var id = tr.data("id");
$.ajax({
type: "POST",
url: "/File/FileDownload",
//contentType: false,
//processData: false,
//dataType: "json",
data: { fileId: id },
success: function (data) {
$('#uploadStatus').html("ok");
},
error: function (err) {
alert(err.statusText);
}
});
});
and controller:
[HttpPost]
public FileResult FileDownload(int? fileId)
{
FileDBEntities db = new FileDBEntities();
tblFile file = db.tblFiles.ToList().Find(p => p.id == fileId.Value);
return File(file.Data, file.ContentType, file.Name);
}
with simple download link in razor it works, but not with ajax.
What am I doing wrong here?
Why not simple use
tab.on("click", ".FileDownload", function (e) {
//$('#uploadStatus').html("ok");
var tr = $(this).closest("tr");
var id = tr.data("id");
window.location = window.location.origin + '/File/FileDownload?fileId=' + id;
});
[HttpGet]
public FileResult FileDownload(int? fileId)
With the help of an input, I want to upload photos using the ajaxPost method. The code you tried is as follows.
HTML;
<input type="file" class="form-control" id="update-category-photo" accept=".jpg,.png,.gif,.JPEG,.JPG" />
Javascript;
function updateCategory() {
var fileUpload = $("#update-category-photo").get(0);
var files = fileUpload.files;
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append('categoryImage', files[i]);
}
postAjax("/Admin/Category/UpdateCategory", {
categoryName: $("#update-category-name").val(),
categoryId: $("#update-category-id").val(),
formData
} , function (result) {
console.log(result);
});
}
And base:> Admin/Category Controller
[HttpPost]
public JsonResult UpdateCategory(int categoryId, string categoryName)
{
return Json("ok:" + Request.Files.Count, 0);//just test now
}
When I just want to post, I get the error "Uncaught TypeError: Illegal invocation".
this answer;
var file = $("#update-category-photo").get(0).files;
var data = new FormData();
data.append("CategoryPhoto", file[0]);
data.append("CategoryId", $("#update-category-id").val());
data.append("CategoryName", $("#update-category-name").val());
$.ajax({
type: 'POST',
url: '/Admin/Category/UpdateCategory',
data: data,
contentType: false,
processData: false,
success: function (result) {
console.log(result);
}
});
And use ViewModel on controller action
I'm trying to send two lists of JSON, a DateTime, int, string, and file to a C# controller via JQuery AJAX POST request.
All data sends fine except the two object arrays, they send nothing.
I've tried changing them from a list of objects to a list of strings to convert from there, but the array is received as one long string, making it nonconvertible via JsonConvert in Newtonsoft.Json.
I've tried logging the formdata objects in order to check their validity, and they seem fine in console. I'm not entirely sure where I've messed up.
Here is my JS:
var formData = new FormData();
formData.append("assignedUsers", JSON.stringify(assignedUsers));
formData.append("ccUsers", JSON.stringify(ccUsers));
formData.append("dueDate", $("#DueDate").val());
formData.append("goalClassID", parseInt(goalClassID));
formData.append("goalDescription", $("#GoalDescription").val());
formData.append("file", document.getElementById("GoalFile").files[0]);
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
$.ajax({
url: api + "main/CreateGoal",
type: "POST",
data: formData,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function (result) {
if (result) {
toastr.success("Goal successfully created");
} else {
toastr.error("Goal creation failed.");
}
}
})
This is my C# Controller:
public bool CreateGoal([FromForm]List<User>AssignedUsers, [FromForm]List<User>CCUsers, [FromForm]DateTime DueDate, [FromForm]int GoalClassID, [FromForm]string GoalDescription, [FromForm]IFormFile File = null)
This is User class
public class User : Base
{
public string UUID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public int Permission { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
}
Both object arrays are empty because you are posting them as json, but all the data is posted as form-data and [FromForm] expects input to be form-data of special format. Everything is working fine for primitive values because they added to FormData like this
formData.append(key, value)
as expected. But when you need to pass an array of objects it must be of the following format
formData.append("obj[0].Field1", field1Val)
formData.append("obj[0].Field2", field2Val)
formData.append("obj[0].Field3", field3Val)
...
formData.append("obj[1].Field1", field1Val)
formData.append("obj[1].Field2", field2Val)
formData.append("obj[1].Field3", field3Val)
So you need to update your code to something like this
var formData = new FormData();
formData.append("assignedUsers[0].uuid", assignedUsers[0].uuid);
formData.append("assignedUsers[0].firstName", assignedUsers[0].firstName);
...
formData.append("assignedUsers[1].uuid", assignedUsers[1].uuid);
formData.append("assignedUsers[1].firstName", assignedUsers[1].firstName);
...
formData.append("dueDate", $("#DueDate").val());
formData.append("goalClassID", parseInt(goalClassID));
formData.append("goalDescription", $("#GoalDescription").val());
formData.append("file", document.getElementById("GoalFile").files[0]);
Well, since this is not very good way to write code you would like to create a function doing it for you. The final solution is
function addUsers(formdata, users, name) {
for (var i = 0; i < users.length; i++) {
addSingleUser(formdata, users[i], name + "[" + i + "]");
}
}
function addSingleUser(formdata, user, name) {
for (var key in user) {
formdata.append(name + "." + key, user[key]);
}
}
var formData = new FormData();
formData.append("dueDate", $("#DueDate").val());
formData.append("goalClassID", parseInt(goalClassID));
formData.append("goalDescription", $("#GoalDescription").val());
formData.append("file", document.getElementById("GoalFile").files[0]);
addUsers(formData, assignedUsers, "assignedUsers")
addUsers(formData, ccUsers, "ccUsers")
$.ajax({
url: "/Home/CreateGoal",
type: "POST",
data: formData,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function (result) {
if (result) {
toastr.success("Goal successfully created");
} else {
toastr.error("Goal creation failed.");
}
}
})
So due to the way the ajax call needs to handle files it does not also process the models in the array as json objects. So, I made a change where the first method will return the created object and the second method will then accept the file.
C# Controller
[HttpPost("CreateGoal")]
public Goal CreateGoal(List<User> AssignedUsers, List<User>CCUsers, DateTime DueDate, int GoalClassID, string GoalDescription)
{
try
{
//Code to save new goal model
return goal;
}
catch (Exception e)
{
return null;
}
}
[HttpPost("CreateGoalFile")]
public bool CreateGoalFile([FromForm] int GoalID, [FromForm]IFormFile File)
{
try
{
//Code to save file and make database relation
return true;
}
catch (Exception)
{
return false;
}
}
Javascript solution
$.post(api + "main/CreateGoal",
{ AssignedUsers: assignedUsers, CCUsers: ccUsers, DueDate: $("#DueDate").val(), GoalClassID: parseInt(goalClassID), GoalDescription: $("#GoalDescription").val() },
function (result) {
if (document.getElementById("GoalFile").files[0] != null) {
var formData = new FormData();
formData.append("goalID", result.id);
formData.append("file", document.getElementById("GoalFile").files[0]);
$.ajax({
url: api + "main/CreateGoalFile",
type: "POST",
data: formData,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function (result) {
if (result) {
toastr.success("File uploaded sucessfully created");
} else {
toastr.error("File uploaded failed.");
}
}
})
}
toastr.success("Goal successfully created");
}
)
I am calling this function to send a file via post:
function AddFileHandler() {
return $.ajax({
processData: false,
contentType: false,
type: "POST",
url: '#Url.Action("AddFile", "SomeController")',
data: getFile()
})
}
In my controller, there is this method which produces an error on the first line:
[HttpPost]
public string AddFile()
{
var attachedFile = Request.Form.Files["CsvDoc"]; // there is an error of wrong contentType
return "";
}
My getFile method optains data like this:
function getFile() {
var input = document.getElementById("csvFile");
if (!input || !input.files || !input.files[0]) {
return ";";
}
console.log(input.files[0]); //inputs my file correctly
var data = new FormData();
data.append("CsvDoc", input.files[0]);
}
What exactly am I doing wrong? Does it matter what is in the html?
You're forgetting to return anything from getFile()
simply add
return data;