Link to dropzone: https://github.com/enyo/dropzone
I am trying to use dropzone as my file upload handler, using angularjs and MVC5.
The issue is I can't seem to get the Http post to go to the MVC 5 backend from angularjs service.
I want to post the files along with other values like action, and a string value named "values"
Below is the code ( in service, angularjs)
sendProductFiles: function (act, file, val) {
return $http.post('/attributes/uploads', $.param({
action: act,
files: file,
values: val
}),
{
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
})
}
In control (angular)
$scope.intakeUpload = function (files) {
var fd = new FormData();
for (var i = 0; i < files.length; i++)
fd.append('file', files[i]);
AttributionViewService.sendProductFiles("addAttr", fd, $scope.selectedValues).then(function (res) {
}, function (err) {
});
}
Dropzone.options.myAwesomeDropzone = {
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
// Dropzone settings
init: function () {
var myDropzone = this;
this.element.querySelector("button[type=submit]").addEventListener("click", function (e) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
this.on("sendingmultiple", function (files) {
$scope.intakeUpload(files);
});
this.on("addedfile", function (file) {
file.previewElement.addEventListener("click", function () { this.removeFile(file); });
});
}
}
In MVC 5 control
[HttpPost]
[Route("attributes/uploads")]
public ActionResult AcceptUploads(string action, HttpPostedFile[] files, string values)
{
if (files.Length <= 0)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
foreach (var file in files)
{
System.Diagnostics.Debug.WriteLine(file.FileName);
}
System.Diagnostics.Debug.WriteLine(values);
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
In the current state I am getting a jquery error
jquery.js:8458 Uncaught TypeError: Illegal invocation
Edit, also tried the following:
Angular Service
sendProductFiles: function (act, file, val) {
return $http.post('/attributes/uploads', $.param({
action: act,
files: file,
values: val
}), {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Fixed it!
$scope.intakeUpload = function (files) {
var fd = new FormData();
for (var i = 0; i < files.length; i++)
fd.append('files', files[i]);
fd.append("action", "addAttr");
fd.append("values", $scope.selectedValues);
AttributionViewService.sendProductFiles(fd).then(function (res) {
}, function (err) {
});
}
[HttpPost]
[Route("attributes/uploads")]
public ActionResult AcceptUploads(string action, IEnumerable<HttpPostedFileBase> files, string values)
{
if (files.Count() <= 0)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
foreach (var file in files)
{
System.Diagnostics.Debug.WriteLine(file.FileName);
}
System.Diagnostics.Debug.WriteLine(values);
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Related
This is the image of form which I have designed in my project Now my requirement is to upload multiple files and with other form values over a single backend call.
<script>
<form class="form-horizontal" name="addColorForm" id="addColorForm"
enctype="multipart/form-data"
method="POST">
//Colour Name and Code fileds
//Files Uploader Plugin (Dropzone)
<input type="file" name="artworkFiles[]" style="visibility: hidden"/>
</form>
Now my script part
<script>
var validCode = function () { // my custom validation };
FormValidation.validators.validCode = validCode;
FormValidation.formValidation(
document.getElementById('addColorForm'),
{
fields: {
colorName: {
validators: {
notEmpty: {
message: '${message(code:"blank.error.message", default:"This field must be entered")}'
},
}
},
},
plugins: { //Learn more: https://formvalidation.io/guide/plugins
trigger: new FormValidation.plugins.Trigger(),
// Bootstrap Framework Integration
bootstrap: new FormValidation.plugins.Bootstrap(),
// Validate fields when clicking the Submit button
submitButton: new FormValidation.plugins.SubmitButton(),
// Submit the form when all fields are valid
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
}
}
).on('core.form.valid', function () {
saveColor();
});
function saveColor() {
var url = "url";
var form = $("#createArtworkForm");
var formData = new FormData(form[0]);
$.ajax({
url: url,
type: 'POST',
enctype: 'multipart/form-data',
data: formData,
success: function (data) {},
cache: false,
contentType: false,
processData: false,
error: function () { }
});
}
var artworkColorsFiles = $('#kt_dropzone').dropzone({
url: "https://www.google.com", // Set the url for your upload script location
paramName: "media", // The name that will be used to transfer the file
maxFiles: 1,
maxFilesize: 40, // MB
addRemoveLinks: true,
acceptedFiles: "image/*",
autoProcessQueue: false,
accept: function (file) {
//Logic to add multiple files in an input type hidden which is declared above
let fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onloadend = function () {
let content = fileReader.result;
$('#artworkFiles').val(content);
file.previewElement.classList.add("dz-success");
}
file.previewElement.classList.add("dz-complete");
}
});
</script>
My questions is how to implement this or how should i add my all files(max 3) in a input type file field declared as visibility hidden.
The same I did in my project here is the code hope it will help you.
you have to use the dropzone function to send file and form data in sendingmultiple function you have to add a loop through your formdata enter code here
var data = $("form#OpportunityForm").serializeArray();
$.each(data, function (key, el) {
.append(el.name, el.value);
});
$(document).ready(function () {
zdrop = new Dropzone('#dropzone', {
url: '#Url.Action("SaveOpportunity", "Masters")',
maxFiles: 500,
maxFilesize: 300,
parallelUploads: 100,
addRemoveLinks: true,
autoProcessQueue: false,
uploadMultiple: true,
removeFilePromise: function () {
return new Promise((resolve, reject) => {
let rand = Math.floor(Math.random() * 3)
console.log(rand);
if (rand == 0) reject('didnt remove properly');
if (rand > 0) resolve();
});
},
sendingmultiple: function (file, xhr, formData) {
var data = $("form#OpportunityForm").serializeArray();
$.each(data, function (key, el) {
.append(el.name, el.value);
});
debugger
$("form#OpportunityForm").find("input[type=file]").each(function (index, field) {
const file = field.files[0];
formData.append('itemfile', file);
});
},
successmultiple: function (file, responseText) {
jQuery('form#OpportunityForm').find('textarea, input').each(function () {
jQuery(this).val('');
});
clear();
swal.fire("Opportunity Details Saved!", "Opportunity details Saved Successfully!", "success");
OpportunityMstList();
GetOpportunityMstList();
location.reload();
$("#myModal").modal('hide');
},
});
after adding this on the form submit button click you have to add this for creating blob file when you post data without image file.
jQuery(document).on('click', 'button#saveOpportunity', function (e) {
e.preventDefault();
if ($("#OpportunityForm").validate().form()) {
if (zdrop.files.length == 0) {
var blob = new Blob();
blob.upload = { 'chunked': zdrop.defaultOptions.chunking };
zdrop.uploadFile(blob); // just submit the form
} else if (zdrop.getRejectedFiles().length > 0) {
alert("The attached file is invalid");
} else {
zdrop.processQueue();
}
}
});
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;
}
}
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 have an ASP.NET MVC Application where I have a method, which returns a list of Objects:
public List<FileObject> GetAllFilesFromDirectory()
{
string filePath = #"C:\FilesToWatch";
string[] fileEntries = Directory.GetFiles(filePath, "*.txt", SearchOption.TopDirectoryOnly);
FileObject fo;
List<FileObject> list = new List<FileObject>();
foreach (var file in fileEntries)
{
FileInfo info = new FileInfo(file);
fo = new FileObject
{
FileName = info.Name, //asdf.txt
FilePath = info.FullName //C:\FilesToWatch\asdf.txt
};
list.Add(fo);
}
return list;
}
Now I want to return this list in javascript:
$.ajax({
type: "GET",
url: "Home/GetAllFilesFromDirectory",
data: ???,
success: function () {
console.log('success');
},
error: function () {
console.log('error');
},
complete: function (data) {
console.log('complete');
}
});
I know, that I have to add the data: attribute, but I do not really know, what I should write after data: to return this list.
You do not need to pass data as your controllerAction accepting no arguments. Here is more clear result you can return from your controllerAction as follow:
public ActionResult GetAllFilesFromDirectory()
{
string filePath = #"C:\FilesToWatch";
string[] fileEntries = Directory.GetFiles(filePath, "*.txt",
SearchOption.TopDirectoryOnly);
FileObject fo;
List<FileObject> list = new List<FileObject>();
foreach (var file in fileEntries)
{
FileInfo info = new FileInfo(file);
fo = new FileObject
{
FileName = info.Name, //asdf.txt
FilePath = info.FullName //C:\FilesToWatch\asdf.txt
};
list.Add(fo);
}
return Json(new { filesList = list }, JsonRequestBehaviour.AllowGet);
}
And then you can read the response in ajax as follow:
$.ajax({
type: "GET",
url: "Home/GetAllFilesFromDirectory",
success: function (resp) {
if(resp.filesList)
{
$.each(function( index, element ) {
console.log(element.FileName ); // i.e log the file name
});
}
},
error: function () {
console.log('error');
},
complete: function (data) {
console.log('complete');
}
});
I am using angularjs. I have created a file upload function using angularjs with laravel. The file upload with FormData is working fine. But when I try to send file through PUT method there is no response from the server side.
I have gone through the following answers.
Uploading a file with jquery and sending as a PUT and How to upload a file using an HTTP "PUT" using JQuery? but I cannot able to find solution.
Here is my code.
<input type="file" ng-file-model = "formData.files" multiple>
The directive for my code
app.directive('ngFileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.ngFileModel);
var isMultiple = attrs.multiple;
var modelSetter = model.assign;
element.bind('change', function () {
var values = [];
angular.forEach(element[0].files, function (item) {
var value = item;
values.push(value);
});
scope.$apply(function () {
if (isMultiple) {
modelSetter(scope, values);
} else {
modelSetter(scope, values[0]);
}
});
});
}
};
}]);
Here is my function which converts my form data into FormData
constructFormData : function( data ) {
var fd = new FormData();
for (var key in data) {
var value = data[key];
angular.forEach(data, function (file, i) {
fd.append('files['+i+']', file);
});
}
return fd;
},
Here is my Controller
var formData = GeneralService.constructFormData($scope.formData);
FileService.update( formData )
.success(function( data ){
if(data.status == 403) {
$location.path('/403');
}
if(data.success) {
console.log(data);
} else {
ValidationService.showValidationErrors(data.errors);
}
});
Here is my service
update : function(formData) {
return $http({
method: 'PUT',
url: $rootScope.baseurl +'/files',
data: formData,
dataType: 'json',
headers: {'Content-Type': undefined}
});
},
The Server side (laravel)
routes.php
Route::put('/files', ['uses' => 'FilesController#update']);
FilesController
public function update(Request $request) {
$data = $request->all();
print_r($data);
}
the above print_r function displays nothing.
I am get the posted data using print_r($request->all());, It gives empty data. I don't know where I make mistake. If I am asking this question by wrong please apologize.
I have the same issue and finally i found this code
var formData = new FormData();
angular.forEach($scope.data, function (value, key) {
formData.set(key, value);
});
$http.post(uploadUrl, formData, {
transformRequest: angular.identity,
headers : {'Content-Type': undefined}
});