Ajax Call to save images in mvc - javascript

I Having issue in uploading images, I want to upload four images individually in MVC as shown in below figure(Please click on "Upload Image File" link to show the image), If we choose one file the particular picture wants to save and it wants to show the preview with proper file name as heading. please help me.. thanks in Advance
Upload Image File

Question is not clear but this is a good solution for uploading in MVC using Ajax:
File Upload HTML
<div style="display:none;">
<img id="image" alt="" src="" class="img-responsive">
</div>
<div id="fileUpload">
<span>Choose Image</span>
<input id="txtUploadFile" type="file" name="files" class="upload" />
</div>
#Html.Partial("~/Views/Shared/_UploadPartial.cshtml")
Create a Partial View or added to HTML
**if you create a partial view for below code can use it anywhere on site, or create a .js file either is way will work well.
<script>
var model = #Html.Raw(Json.Encode(Model));
$('#txtUploadFile').on('change', function (e) {
var files = e.target.files;
if (files.length > 0) {
if (window.FormData !== undefined) {
var data = new FormData();
for (var x = 0; x < files.length; x++) {
data.append("file" + x, files[x]);
}
$.ajax({
type: "POST",
url: '/User/UploadFile/' + model,
contentType: false,
processData: false,
data: data,
success: function (result) {
$('#image').attr('src', '#Url.Content("~/Content/img/")' + result.fileName);
},
error: function (xhr, status, p3, p4) {
var err = "Error " + " " + status + " " + p3 + " " + p4;
if (xhr.responseText && xhr.responseText[0] == "{")
err = JSON.parse(xhr.responseText).Message;
console.log(err);
}
});
} else {
alert("This browser doesn't support HTML5 file uploads!");
}
}
});
Controller Method
[HttpPost]
public JsonResult UploadFile(string id)
{
var path = "";
var fileExtension = "";
var fileName = "";
if (Request.Files.Count > 0)
{
HttpPostedFileBase file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
fileName = Path.GetFileName(file.FileName);
fileExtension = Path.GetExtension(file.FileName);
if (id != "null")
{
//do bits, save to DB etc./..
file.SaveAs(path);
}
}
}
return Json(new { fileName = fileName });
}
Explanation
The file upload html with id="image" is for when you select a image from your directory after pressing the txtUploadFile input, then the partial view or js file or inline script, depending on approach taken will fire the onchange function: $('#txtUploadFile').on('change', function (e) this will do a ajax call to your method in your controller - you can do all your logic like saving to the database ect... from here.
The controller function is then returning the fileName to the success function of the ajax call, assuming you have saved the image somewhere you can then use result.fileName, or whatever to get your image:
$('#image').attr('src', '#Url.Content("~/Content/img/")' + result.fileName);
As you can see the nested image attribute in the file upload HTML is being changed to the newly uploaded image.
Hope this helps.

Related

Kendo Upload cannot get Byte array of selected file

How can take the byte array data of selected file? from select event i can get e.files[0].rawFile but i cannot find where is stored the byte[]. i want this data on client side
I found the documentation pretty poor on this matter as well. The documentation is geared at using a REST endpoint to do server side processing of the file. Most of the examples of client side processing are just for showing the file names, which isn't super useful if you want to do any meaningful client-side validation of the content of the file. In my case, I have CSV files I want to do some pre-processing on the client side. The trick is you need to use the HTML5 a FileReader. Here is an example in AngularJS where $ctrl.fileContent will have the content of a CSV file.
controller: ['$scope', function ($scope) {
var $ctrl = this;
// function called by kendo upload component
$ctrl.onSelect = function(e) {
var message = e.files.map(function(file) {
return $ctrl.readFile(file);
}).join(', ');
// log file names being uploaded
console.log('event :: files select (' + message + ')');
};
// read file and do basic validation
$ctrl.readFile = function(file) {
var reader = new FileReader();
reader.onload = function(e) {
var text = reader.result;
console.log('File contents :: ' + text);
$ctrl.fileContent = text;
};
reader.readAsText(file.rawFile);
// return file name
return file.name;
};
// function called by kendo upload component
$ctrl.onUpload = function(e) {
// todo
console.log('Uploading file');
console.log($ctrl.fileContent);
};
}]
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="content-panel">
<div class="row">
<div class="form-group col-lg-3 col-md-3 col-sm-6 col-xs-12">
<h4>Upload CSV files</h4>
<input name="files"
type="file"
kendo-upload
k-async="{ saveUrl: '$ctrl.save', removeUrl: 'remove', autoUpload: false }"
k-select="$ctrl.onSelect"
k-validation="{ allowedExtensions: ['csv']}"
k-upload="$ctrl.onUpload"
/>
</div>
</div>
</div>
try something like this:
function(data) {
data = btoa(data);
var bytesArr = [];
for(var i = 0; i < data.length; i++) {
bytesArr.push(data.charCodeAt(i));
}
return new Uint8Array(bytesArr);
}

CKEditor response callback after file attached successfully

Using CKEditor to send email and upload attachments. Below is the minimal configuration I've from this source.
CKEDITOR.replace('email.Message', {
filebrowserUploadUrl: '/Controller/UploadAttachment',
extraPlugins: 'attach', // attachment plugin
toolbar: this.customToolbar, //use custom toolbar
autoCloseUpload: true, //autoClose attachment container on attachment upload
validateSize: 30, //30mb size limit
onAttachmentUpload: function(response) {
/*
the following code just utilizes the attachment upload response to generate
ticket-attachment on your page
*/
attachment_id = $(response).attr('data-id');
if (attachment_id) {
attachment = $(response).html();
$closeButton = $('<span class="attachment-close">').text('x').on('click', closeButtonEvent)
$('.ticket-attachment-container').show()
.append($('<div>', {
class: 'ticket-attachment'
}).html(attachment).append($closeButton))
.append($('<input>', {
type: 'hidden',
name: 'attachment_ids[]'
}).val(attachment_id));
}
}
});
On the Controller side I've got below code
const string scriptTag = "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction({0}, '{1}', '{2}')</script>";
public ContentResult UploadAttachment()
{
string basePath = HttpContext.Server.MapPath("~/assets/Images/");
const string baseUrl = #"/ckfinder/userfiles/";
var funcNum = 0;
int.TryParse(Request["CKEditorFuncNum"], out funcNum);
if (Request.Files == null || Request.Files.Count < 1)
return BuildReturnScript(funcNum, null, "No file has been sent");
if (!System.IO.Directory.Exists(basePath))
return BuildReturnScript(funcNum, null, "basePath folder doesn't exist");
var receivedFile = Request.Files[0];
var fileName = receivedFile.FileName;
if (string.IsNullOrEmpty(fileName)) {
return BuildReturnScript(funcNum, null, "File name is empty");
}
var sFileName = System.IO.Path.GetFileName(fileName);
var nameWithFullPath = System.IO.Path.Combine(basePath, sFileName);
//Note: you may want to consider using your own naming convention for files, as this is vulnerable to overwrites
//e.g. at the moment if two users uploaded a file called image1.jpg, one would clash with the other.
//In the past, I've used Guid.NewGuid() combined with the file extension to ensure uniqueness.
receivedFile.SaveAs(nameWithFullPath);
var url = baseUrl + sFileName;
return BuildReturnScript(funcNum, url, null);
}
private ContentResult BuildReturnScript(int functionNumber, string url, string errorMessage) {
return Content(
string.Format(scriptTag, functionNumber, HttpUtility.JavaScriptStringEncode(url ? ? ""), HttpUtility.JavaScriptStringEncode(errorMessage ? ? "")),
"text/html"
);
}
Below is the response I get back inside onAttachmentUpload - function
<form enctype="multipart/form-data" method="POST" dir="ltr" lang="en" action="/Controller/UploadAttachment?CKEditor=email_Message&CKEditorFuncNum=0&langCode=en">
<label id="cke_73_label" for="cke_74_fileInput_input" style="display:none"></label>
<input style="width:100%" id="cke_74_fileInput_input" aria-labelledby="cke_73_label" type="file" name="attachment" size="38">
</form>
<script>
window.parent.CKEDITOR.tools.callFunction(98);
window.onbeforeunload = function({
window.parent.CKEDITOR.tools.callFunction(99)
});
</script>
But it is expecting some data-id for attachment id. I've no idea what the response should look like. Could someone tell me what the actual response should look like and what is the data-id its expecting as attr in response? Also, is there anyway I can upload multiple files with this?
This is how I am returning the response now and rendering the attached file. Hope it might help someone in future.
[AcceptVerbs(HttpVerbs.Post)]
public ContentResult UploadAttachment() {
string basePath = HttpContext.Server.MapPath("~/somepath");
var funcNum = 0;
int.TryParse(Request["CKEditorFuncNum"], out funcNum);
if (Request.Files == null || Request.Files.Count < 1)
return Content("No file has been sent");
if (!System.IO.Directory.Exists(basePath))
Directory.CreateDirectory(Path.Combine(basePath));
var receivedFile = Request.Files[0];
var fileName = receivedFile.FileName;
if (string.IsNullOrEmpty(fileName)) {
return Content("File name is empty");
}
var sFileName = System.IO.Path.GetFileName(fileName);
var nameWithFullPath = Path.Combine(basePath, sFileName);
receivedFile.SaveAs(nameWithFullPath);
var content = "<span data-href=\"" + nameWithFullPath + "\" data-id=\"" + funcNum + "\"><i class=\"fa fa-paperclip\"> </i> " + sFileName + "</span>";
return Content(content);
}
and on the JS side I have below code to append the uploaded file name:
CKEDITOR.replace('email.Message', {
filebrowserUploadUrl: '/Controller/UploadAttachment',
extraPlugins: 'attach', // attachment plugin
toolbar: this.customToolbar, //use custom toolbar
autoCloseUpload: true, //autoClose attachment container on attachment upload
validateSize: 30, //30mb size limit
onAttachmentUpload: function(response) {
/*
the following code just utilizes the attachment upload response to generate
ticket-attachment on your page
*/
attachment_id = $(response).attr('data-id');
if (attachment_id) {
attachment = response;
$closeButton = '<span class="attachment-close btn btn-danger float-right" style="margin-top:-7px"><i class="fa fa-trash"></i></span>'; //.on('click', closeButtonEvent)
$respDiv = '<ol class="breadcrumb navbar-breadcrumb" style="padding:18px 15px"><li style="display:block">' + attachment + $closeButton + '</li></ol>';
$('.ticket-attachment-container').show()
.append($('<div>', {
class: 'ticket-attachment'
}).html($respDiv))
.append($('<input>', {
type: 'hidden',
name: 'attachment_ids[]'
}).val(attachment_id));
$('.ticket-attachment-container').on('click', '.attachment-close', function() {
$(this).closest('.ticket-attachment').remove();
if (!$('.ticket-attachment-container .ticket-attachment').length)
$('.ticket-attachment-container').hide();
});
}
}
});

AngularJS image upload preview without directive

I'm uploading files via service:
var addFile = function(files) {
var deferred = $q.defer();
var fd = new FormData();
fd.append("file", files[0]);
$http.post("/files", fd, {
***
})
.success(function(data, status, headers, config) {
***
})
.error(function(err, status) {
***
});
***
};
and in controller I have something like:
uplService.addFile($scope.files).then(function(url) {
$scope.news.Photo = url;
});
and in HTML view:
<input type="file" name="file" onchange="angular.element(this).scope().photoChanged(this.files)" />
before that I uploaded file on-the-go, when I select file it goes directly to server, but now I need to display it in my form when I select it, but upload later, all I see in web is using directives, but how could I organize it without using directives?
Can you try this in your controller to pass your file object here:
$scope.fileReaderSupported = window.FileReader != null;
$scope.photoChanged = function(files){
if (files != null) {
var file = files[0];
if ($scope.fileReaderSupported && file.type.indexOf('image') > -1) {
$timeout(function() {
var fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = function(e) {
$timeout(function(){
$scope.thumbnail.dataUrl = e.target.result;
});
}
});
}
}
};
and on the view
<img ng-show="thumbnail.dataUrl != null" ng-src="{{ thumbnail.dataUrl }}" class="thumb">
demo here
Hope this help
I read this article, which helped me to solve the problem about uploading the image.
If you want to show your selected file, try this:
<img data-ng-src="data:image/png;base64,{{news.Photo}}" id="photo-id"/>
Explanation:
Your property for image in Model/ViewModel/Class must be an array of bytes, like
public byte[] Photo { get; set; }
The data:image/jpeg;base64 defines the byte array from news.Photo so it can be rendered correctly on the clients browser.
The $scope.news.Photo in your case is just an scoped variable which contains the drawed image with byte created by the byte equivalent in the $scope.uploadFile function from article.
I hope it will be also helpful for you.

How to upload base64 image resource with dropzone?

I'm trying to upload generated client side documents (images for the moment) with Dropzone.js.
// .../init.js
var myDropzone = new Dropzone("form.dropzone", {
autoProcessQueue: true
});
Once the client have finished his job, he just have to click a save button which call the save function :
// .../save.js
function save(myDocument) {
var file = {
name: 'Test',
src: myDocument,
};
console.log(myDocument);
myDropzone.addFile(file);
}
The console.log() correctly return me the content of my document
data:image/png;base64,iVBORw0KGgoAAAANS...
At this point, we can see the progress bar uploading the document in the drop zone but the upload failed.
Here is my (standart dropzone) HTML form :
<form action="/upload" enctype="multipart/form-data" method="post" class="dropzone">
<div class="dz-default dz-message"><span>Drop files here to upload</span></div>
<div class="fallback">
<input name="file" type="file" />
</div>
</form>
I got a Symfony2 controller who receive the post request.
// Get request
$request = $this->get('request');
// Get files
$files = $request->files;
// Upload
$do = $service->upload($files);
Uploading from the dropzone (by drag and drop or click) is working and the uploads are successfull but using the myDropzone.addFile() function return me an empty object in my controller :
var_dump($files);
return
object(Symfony\Component\HttpFoundation\FileBag)#11 (1) {
["parameters":protected]=>
array(0) {
}
}
I think i don't setup correctly my var file in the save function.
I tryied to create JS image (var img = new Image() ...) but without any success.
Thanks for your help !
Finally i found a working solution without creating canvas :
function dataURItoBlob(dataURI) {
'use strict'
var byteString,
mimestring
if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
byteString = atob(dataURI.split(',')[1])
} else {
byteString = decodeURI(dataURI.split(',')[1])
}
mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]
var content = new Array();
for (var i = 0; i < byteString.length; i++) {
content[i] = byteString.charCodeAt(i)
}
return new Blob([new Uint8Array(content)], {type: mimestring});
}
And the save function :
function save(dataURI) {
var blob = dataURItoBlob(dataURI);
myDropzone.addFile(blob);
}
The file appears correctly in dropzone and is successfully uploaded.
I still have to work on the filename (my document is named "blob").
The dataURItoBlob function have been found here : Convert Data URI to File then append to FormData
[EDIT] : I finally wrote the function in dropzone to do this job. You can check it here : https://github.com/CasperArGh/dropzone
And you can use it like this :
var dataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmAAAAKwCAYAAA...';
myDropzone.addBlob(dataURI, 'test.png');
I can't comment currently and wanted to send this to you.
I know you found your answer, but I had some trouble using your Git code and reshaped it a little for my needs, but I am about 100% positive this will work for EVERY possible need to add a file or a blob or anything and be able to apply a name to it.
Dropzone.prototype.addFileName = function(file, name) {
file.name = name;
file.upload = {
progress: 0,
total: file.size,
bytesSent: 0
};
this.files.push(file);
file.status = Dropzone.ADDED;
this.emit("addedfile", file);
this._enqueueThumbnail(file);
return this.accept(file, (function(_this) {
return function(error) {
if (error) {
file.accepted = false;
_this._errorProcessing([file], error);
} else {
file.accepted = true;
if (_this.options.autoQueue) {
_this.enqueueFile(file);
}
}
return _this._updateMaxFilesReachedClass();
};
})(this));
};
If this is added to dropzone.js (I did just below the line with Dropzone.prototype.addFile = function(file) { potentially line 1110.
Works like a charm and used just the same as any other. myDropzone.addFileName(file,name)!
Hopefully someone finds this useful and doesn't need to recreate it!
1) You say that: "Once the client have finished his job, he just have to click a save button which call the save function:"
This implies that you set autoProcessQueue: false and intercept the button click, to execute the saveFile() function.
$("#submitButton").click(function(e) {
// let the event not bubble up
e.preventDefault();
e.stopPropagation();
// process the uploads
myDropzone.processQueue();
});
2) check form action
Check that your form action="/upload" is routed correctly to your SF controller & action.
3) Example Code
You may find a full example over at the official Wiki
4) Ok, thanks to your comments, i understood the question better:
"How can i save my base64 image resource with dropzone?"
You need to embedd the image content as value
// base64 data
var dataURL = canvas.toDataURL();
// insert the data into the form
document.getElementById('image').value = canvas.toDataURL('image/png');
//or jQ: $('#img').val(canvas.toDataURL("image/png"));
// trigger submit of the form
document.forms["form1"].submit();
You might run into trouble doing this and might need to set the "origin-clean" flag to "true". see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#security-with-canvas-elements
how to save html5 canvas to server

Image upload to Facebook from HTML drag and drop

I've got a PHP script that can upload images stored on my server to a Facebook post. I've tried and tested it and the post gets to Facebook just fine.
I also have a drag and drop area on my webpage, based on this tutorial. What I've hit a brick wall on is getting the file dropped onto the DOM element that I'm listening to and then passing it over to the PHP script or, for that matter, a Javascript function.
I suspect that Javascript might be my best option, so I've looked at Dropzone.js but it appears to require that the image first goes to my server and then onto Facebook - I'd really like to avoid that for storage and upload time reasons.
I think in terms of a Javascript solution it's got something to do with FileReader() and here's my code so far:
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
if (!f.type.match('image.*')) { continue; }
var fileReader = new FileReader();
fileReader.onload = (function(theFile) {
return function(e) {
var blob = e.target.result;
var fd = new FormData();
fd.append("access_token",fbAccessToken);
fd.append("source", blob);fd.append("message","This is another post test...");
try{
$.ajax({
url:"https://graph.facebook.com/" + fbuserid + "/photos?access_token=" + fbAccessToken,
type:"POST",
data:fd,
processData:false,
contentType:false,
cache:false,
console.log("success " + data);
},
error:function(shr,status,data){
console.log("error " + data + " Status " + shr.status);
},
complete:function(){
console.log("Ajax Complete");
}
});
}catch(e){console.log(e);}
};})(f);
fileReader.readAsDataURL(f);
}
}
and I can see that raw image data is accessible through there but then how can I pass that to the Formdata?

Categories

Resources