Take a look below code I'm trying to alert the value of i inside the reader.onloadend it's not showing properly, It's showing max value of i, i.e if i add 3 images i alerting only three it should show 0,1 and 3.
$("#files2").change(function()
{
var src=$("#files2").val();
if(src!="")
{
formdata= new FormData();
var numfiles=this.files.length;
var i, file, progress, size;
for(i=0;i<numfiles;i++)
{
//alert(i);
file = this.files[i];
size = this.files[i].size;
name = this.files[i].name;
if (!!file.type.match(/image.*/))
{
if((Math.round(size))<=(1024*1024))
{
var reader = new FileReader();
reader.readAsDataURL(file);
$("#preview").show();
$('#preview').html("");
//<img src="img/remove.png"/>
//style='margin-left: -16px;margin-top: -6px;'
alert(i);
reader.onloadend = function(e)
{
var image = $('<img id="im'+i+'" style="float:left; height: 150px; width: 125px; margin-left: 5px; margin-right: 10px; margin-bottom: 10px;">').attr('src',e.target.result);
var image1 = $('<img onclick="$(this).remove();$("#im1").remove();" style=" margin-left: -25px;margin-top: -1px;z-index: 1;position: absolute; ">').attr('src','img/remove.png');
$(image).appendTo('#preview');
$(image1).appendTo('#preview');
};
formdata.append("files2[]", file);
if(i==(numfiles-1))
{
$(".nextim").click(function(){
$.ajax(
{
url: "upload.php?contactid=<?php echo $id1; ?>&postid=<?php echo $id2; ?>",
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function(res)
{
if(res!="0")
$("#info").html("Successfully Uploaded");
else
$("#info").html("Error in upload. Retry");
}
});
return false;
});
}
}
else
{
$("#info").html(name+"Size limit exceeded");
$("#preview").hide();
return;
}
}
else
{
$("#info").html(name+"Not image file");
$("#preview").hide();
return;
}
}
}
else
{
$("#info").html("Select an image file");
$("#preview").hide();
return;
}
return false;
});
From what I understand you should be looping through the number of files that are used. Since you have not showed us how variable i is initialized, I tried using the name as an example. Hope this might help you :)
for (var count = 0; count < files.length; count ++) {
(function(file) {
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
alert(name );
}
})(files[count]);
}
Related
I have a web application that create post with 15 images maximum and other data, I am using AJAX request to send all data with images in one request but I got this error:
An error occurred during the serialization or de-serialization process with JSON JavaScriptSerializer. The length of the string exceeds the value set in the MaxJsonLength property.
I am trying to compress the images before uploading but same problem still.
That's the JS code:
function readURL(input) {
var files = input.files;
for (var index = 0; index < files.length; index++) {
var mainImage = "";
if (files && files[index]) {
var reader = new FileReader();
reader.onload = function (e) {
const imgElement = document.createElement("img");
imgElement.src = event.target.result;
if ($(".imgUpload li").length <= 15) {
imgElement.onload = function (e) {
const canvas = document.createElement("canvas");
const MAX_WIDTH = 960;
const scaleSize = MAX_WIDTH / e.target.width;
canvas.width = MAX_WIDTH;
canvas.height = e.target.height * scaleSize;
const ctx = canvas.getContext("2d");
ctx.drawImage(e.target, 0, 0, canvas.width, canvas.height);
const srcEncoded = ctx.canvas.toDataURL(e.target, "image/jpeg");
// you can send srcEncoded to the server
$(".imgUpload").append('<li class="d-inline-block vTop position-relative mr-3 ' + mainImage + '"><a class="removeImg center w3-text-white fullRadius osRedBg position-absolute" data-ghost="removeImg" href="javascript:;"><svg viewBox="0 0 32 32" width="20" height="20" class="d-inline-block vMiddle" data-name="IconClose"><path fill="#ffffff" stroke="#fff" stroke-width="1" d="M25.333 8.547l-1.88-1.88-7.453 7.453-7.453-7.453-1.88 1.88 7.453 7.453-7.453 7.453 1.88 1.88 7.453-7.453 7.453 7.453 1.88-1.88-7.453-7.453z"></path></svg></a><img class="ad-img" alt="" src="' + srcEncoded + '"></li>');
if ($('.imgUpload li.mainImage').length == 0) {
$('.imgUpload li:nth-child(2)').addClass("mainImage");
}
if ($(".imgUpload li").length > 2) {
$(".imgValMsg").text("#Messages.ClickToDetectMainImage");
}
};
}
else {
$('.modalCountImgs').modal('show');
}
if ($('.imgUpload li.mainImage').length == 0) {
$('.imgUpload li:nth-child(2)').addClass("mainImage");
}
if ($(".imgUpload li").length > 2) {
$(".imgValMsg").text("#Messages.ClickToDetectMainImage");
}
}
reader.readAsDataURL(files[index]); // convert to base64 string
}
}
}
$("#inputAddImage").change(function () {
var input = this;
var files = this.files;
var validFiles = true;
for (var index = 0; index < files.length; index++) {
var extLogo = files[index].name.split('.').pop().toLowerCase();
if ($.inArray(extLogo, ['gif', 'png', 'jpg', 'jpeg']) == -1) {
validFiles = false;
break;
}
}
if (validFiles) {
readURL(input);
$("#Imgs-error2").removeClass("d-block").addClass("d-none");
}
else {
$("#Imgs-error2").removeClass("d-none").addClass("d-block");
}
$("#Imgs-error").removeClass("d-block").addClass("d-none");
});
and AJAX request:
//Images
var lstImgs = [];
var ImgElements = $(".imgUpload img");
ImgElements.each(function () {
var obj = {
ImageData: $(this).attr("src")
}
lstImgs.push(obj);
});
var productModel = {
CategoryThirdId: $("#CategoryThirdId").val(),
ProductTitle: $("#ProductTitle").val(),
ProductDescription: $("#ProductDescription").val(),
Price: $("#Price").val(),
Images:lstImgs
};
var data = {
model:productModel
};
$.ajax({
method: "post",
url: '#Url.Action("CreateAdvertise", "Advertise")',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (res) {
if (res != null) {
if (res == "ErrorCatalogName") {
$(".danger-product-name").show();
}
}
else {
$(".danger-product-name").hide();
}
$('#overlay').fadeOut();
},
error: function (res) {
$('#overlay').fadeOut();
}
});
At the end my goal is to upload 15 images and other data from client to server witch I use ASP .NET MVC
and the images to be compressed until the user upload an image with 20 MB.
You can't post files as string. Use something like this:
var fd = new FormData();
fd.append( 'file', input.files[0] );
$.ajax({
url: '/Example/SendData',
data: fd,
processData: false,
contentType: false,
type: 'POST',
success: function(data){
alert(data);
}
});
I have a multi-file input field:
<input type="file" class="image_file" multiple>
I am using FileReader to show previews of images whilst they are being uploaded.
I now also want to show a progress bar on each individual image whilst it is being uploaded. Here is what I have tried:
$('.image_file').change(function() {
var input = $(this);
var files = this.files;
var total = files.length;
var url = input.attr('data-url');
for (var i = 0; i < total; i++) {
var formData = new FormData();
var file = files[i];
formData.append('image_file', file);
var reader = new FileReader();
reader.onload = function(e) {
var container = $('.photos .photo:not(.active):first');
if (container.length) {
container.css('background-image', 'url(' + e.target.result + ')').addClass('active uploading');
}
};
reader.readAsDataURL(file);
$.ajax({
type: 'post',
url: url,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
var progressElem = container.find('progress');
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
progressElem.attr({
value: e.loaded,
max: e.total
});
}
}, false);
}
return myXhr;
},
success: function(result) {
if (result.status == true) {
$('.success-message').show();
}
else {
alert('There was an error uploading your file.);
}
}
});
}
});
The issue I am having is on this line in the xhr function:
var progressElem = container.find('progress');
The image preview appears but the AJAX upload isn't working. No errors are shown in the console either. I think because var container was set within the reader.onload function, the xhr function doesn't have access to it.
If I move that var outside of the function, the image upload works but only one image preview and one progress bar is shown.
Does anybody know the correct way to do this?
The problem is that there is a single xhr that is created and deleted when the for loop runs. The previous xhr are destroyed once the code finishes so it will never run.
The way I got round this was to not use jQuery and/or create a new xmlhttprequest for each for loop.
var array = []; //ADDED HERE
$('.image_file').change(function() {
var input = $(this);
var files = this.files;
var total = files.length;
var url = input.attr('data-url');
for (var i = 0; i < total; i++) {
var formData = new FormData();
var file = files[i];
formData.append('image_file', file);
var reader = new FileReader();
reader.onload = function(e) {
var container = $('.photos .photo:not(.active):first');
if (container.length) {
container.css('background-image', 'url(' + e.target.result + ')').addClass('active uploading');
}
};
reader.readAsDataURL(file);
array[array.Length] = $.ajax({ //ADDED HERE
type: 'post',
url: url,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
var progressElem = container.find('progress');
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
progressElem.attr({
value: e.loaded,
max: e.total
});
}
}, false);
}
return myXhr;
},
success: function(result) {
if (result.status == true) {
$('.success-message').show();
} else {
alert('There was an error uploading your file.);
}
}
});
}
});
I need to emphasis that I haven't looked through your code completely but hopefully this will steer you in the right direction.
Looking at your question description, I assume:
Image Preview works since you mentioned "The image preview appears"
Image uploads since you mentioned "If I move that var outside of the function, the image upload works..."
Where is the problem then?
The problem is your variable container is not accessible inside xhr() function as you mentioned already.
What is the solution?
There can be many possible solutions for you problem, but I think moving the ajax request block inside reader.onload is better idea since, the variable container will be accessible to child function and it will be called only if vaild file is being uploaded.
$('.image_file').change(function() {
var input = $(this);
var files = this.files;
var total = files.length;
var url = input.attr('data-url');
for (var i = 0; i < total; i++) {
var formData = new FormData();
var file = files[i];
formData.append('image_file', file);
var reader = new FileReader();
reader.onload = function(e) {
var container = $('.photos .photo:not(.active):first');
if (container.length) {
var ajaxFunction = function() {
var myXhr = $.ajaxSettings.xhr();
var progressElem = this.find('progress');
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
progressElem.attr({
value: e.loaded,
max: e.total
});
}
}, false);
}
return myXhr;
};
container.css('background-image', 'url(' + e.target.result + ')').addClass('active uploading');
$.ajax({
type: 'post',
url: url,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: ajaxFunction.bind(container),
success: function(result) {
if (result.status == true) {
$('.success-message').show();
} else {
alert('There was an error uploading your file.');
}
}
});
}
};
reader.readAsDataURL(file);
}
});
.photo {
display: none;
height: 200px;
width: 200px;
float: left;
}
.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" class="image_file" multiple data-url="http://httpbin.org/post">
<div class="photos">
<div class="photo">
<progress></progress>
</div>
<div class="photo">
<progress></progress>
</div>
</div>
Updated: used bind() function to pass current value of the variable container to the ajaxFunction()
The code below submits file on drop and will call ajaxat the same time but I tried changing it to a way where user can drop files after files and submit it at once.
I wrapped the function that sends file to ajaxwith on click but it is still sending file one by one. Why?
function handleFileUpload(files, obj) {
for (var i = 0; i < files.length; i++) {
var fd = new FormData();
fd.append('file', files[i]);
var status = new createStatusbar(obj); //Using this we can set progress.
status.setFileNameSize(files[i].name, files[i].size);
}
var submit = $("#submit-button-id");
submit.on('click', function(e) {
e.preventDefault();
alert("clicked nest!")
sendFileToServer(fd, status);
});
}
And here is the Web API ajaxcall function:
function sendFileToServer(formData, status) {
var uploadURL = _config.UploadPrismaTemplates;
var extraData = {}; //Extra Data.
var jqXHR = $.ajax({
xhr: function() {
var xhrobj = $.ajaxSettings.xhr();
if (xhrobj.upload) {
xhrobj.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
//Set progress
status.setProgress(percent);
}, false);
}
return xhrobj;
},
url: uploadURL,
type: "POST",
contentType: false, //not to set any content header
processData: false, //not to process data
cache: false,
data: formData,
success: function(data) {
status.setProgress(100);
//$("#status1").append("File upload Done<br>");
alert("set progress success");
},
error: function(xhr, status, error) {
alert(error);
}
});
status.setAbort(jqXHR);
} /*send file to server ends here*/
Here I fixed it ! It will only submit files if clicked.
$(document).ready(function(){
var drop = $('#drag-and-drop-zone');
var uploadBtn = $('#submit-button-id');
drop.on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).css('border', '2px solid #0B85A1');
});
drop.on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
});
var rowCount = 0;
function createStatusbar(drop) {
rowCount++;
var row = "odd";
if (rowCount % 2 == 0) row = "even";
this.statusbar = $("<div class='statusbar " + row + "'></div>");
this.filename = $("<div class='filename'></div>").appendTo(this.statusbar);
this.size = $("<div class='filesize'></div>").appendTo(this.statusbar);
this.progressBar = $("<div class='progressBar'><div></div></div>").appendTo(this.statusbar);
this.abort = $("<div class='abort'>Abort</div>").appendTo(this.statusbar);
$('#display-status-id').append(this.statusbar);
this.setFileNameSize = function (name, size) {
var sizeStr = "";
var sizeKB = size / 1024;
if (parseInt(sizeKB) > 1024) {
var sizeMB = sizeKB / 1024;
sizeStr = sizeMB.toFixed(2) + " MB";
}
else {
sizeStr = sizeKB.toFixed(2) + " KB";
}
this.filename.html(name);
this.size.html(sizeStr);
}
this.setProgress = function (progress) {
var progressBarWidth = progress * this.progressBar.width() / 100;
this.progressBar.find('div').animate({ width: progressBarWidth }, 10).html(progress + "% ");
if (parseInt(progress) >= 100) {
this.abort.hide();
}
}
this.setAbort = function (jqxhr) {
var sb = this.statusbar;
this.abort.click(function () {
jqxhr.abort();
sb.hide();
});
}
}
/*****************************************/
drop.on('drop', function (e) {
$(this).css('border', '2px dotted #0B85A1');
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
if (!files) return;
console.log("drop:", drop);
for (var i = 0; i < files.length; i++) {
var status = new createStatusbar(drop);
status.setFileNameSize(files[i].name, files[i].size);
}
uploadBtn.on('click', function (e) {
var fd = new FormData();
for (var i = 0; i < files.length; i++)
{
fd.append(files[i].name, files[i]);
}
sendFiletoServer(fd);
});
function sendFiletoServer(formData) {
var uploadURL = "";
var extraData = {};
var jqXHR = $.ajax({
xhr: function () {
var xhrobj = $.ajaxSettings.xhr();
if (xhrobj.upload) {
xhrobj.upload.addEventListener('progress', function (event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
Call event.preventDefault() at dragover event of droppable element, use a <button> element for user to click when they want to upload the FormData() object containing the files that they have dropped.
var drop = document.getElementById("drop");
var button = document.getElementById("upload");
var fd = new FormData();
drop.ondragover = function(e) {
e.preventDefault();
}
drop.ondrop = function(e) {
e.preventDefault();
if (e.dataTransfer.types[0] === "Files") {
var file = e.dataTransfer.files[0];
fd.append("files[]", file, file.name);
}
}
button.onclick = function(e) {
console.log([...fd]);
// do ajax stuff with `fd` here
// delete items in `fd` when ajax stuff completes
for (let [key, prop] of [...fd]) {
fd.delete(key)
}
console.log([...fd]);
}
#drop {
width: 300px;
height: 200px;
border: 2px dotted green;
text-align: center;
}
<div id="drop">Drop files</div>
<button id="upload">Upload</button>
Hey guys am new to jQuery,How can I change this javascript code into jQuery functional code so that I call it whenever I want at any object
LIKE: $("#profile_img").uploader();
Apparently this code works fine, but the problem I have is I have to populate the code every time I need to upload a file in a different file input upload.
var input = document.getElementById("choosen_feeds_image"),
formdata = false;
if (window.FormData) {
formdata = new FormData();
document.getElementById("feeds_upload_btn").style.display = "none";
}
if (input.addEventListener) {
input.addEventListener("change", function (evt) {
var i = 0, len = this.files.length, img, reader, file;
document.getElementById("response").innerHTML = ""
for (; i < len; i++) {
file = this.files[i];
if (!!file.type.match(/image.*/)) {
if (window.FileReader) {
reader = new FileReader();
reader.onloadend = function (e) {
showUploadedItem(e.target.result);
};
reader.readAsDataURL(file);
}
if (formdata) {
formdata.append("feeds_image", file);
}
if (formdata) {
$.ajax({
url: "member/feeds_image_upload",
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function (res) {
if (res.length <= 40) {
document.getElementById('feeds_image_response').innerHTML = res;
$("#feeds_image_response").css('display', 'none');
} else {
document.getElementById("response").innerHTML = res;
$("#response").css('display', 'none');
}
}
});
}
} else {
document.getElementById("response").innerHTML = "";
alert("Sorry, You choose unsupported file");
}
}
}), false
};
you can type all inside a function like this
function uploader(){
console.log('myFuntionUploader');
}
and then call the function like this
uploader();
I am trying to add the page_id and page_slug to the loop so that when an image is uploaded the details page id and slug go to.
Normally I would use this: data: { page_id: page_id, page_slug: page_slug }
But formData is there..
(function () {
var input = document.getElementById("images"),
formdata = false;
var page_id = $('#page_id').val();
var page_slug = $('#page_slug').val();
function showUploadedItem (source) {
var list = document.getElementById("image-list"),
li = document.createElement("li"),
img = document.createElement("img");
img.src = source;
li.appendChild(img);
list.appendChild(li);
}
if (window.FormData) {
formdata = new FormData();
document.getElementById("btn").style.display = "none";
}
input.addEventListener("change", function (evt) {
document.getElementById("response").innerHTML = "Uploading . . ."
var i = 0, len = this.files.length, img, reader, file;
for ( ; i < len; i++ ) {
file = this.files[i];
if (!!file.type.match(/image.*/)) {
if ( window.FileReader ) {
reader = new FileReader();
reader.onloadend = function (e) {
showUploadedItem(e.target.result, file.fileName);
};
reader.readAsDataURL(file);
}
if (formdata) {
formdata.append("images[]", file);
}
}
}
if (formdata) {
$.ajax({
url: "admin/pages/upload/",
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function (res) {
document.getElementById("response").innerHTML = res;
}
});
}
}, false);
}());
I do not think you can manipulate the FormData object directly inside the $.ajax or even $.ajaxSetup functions, so adding two calls to append in the following code block should include the required parameters.
if (window.FormData) {
formdata = new FormData();
formdata.append('page_id', page_id);
formdata.append('page_slug', page_slug);
document.getElementById("btn").style.display = "none";
}
The page_id and page_slug values are unique to so do not need appending in the loop; just once after creating the FormData object.
Please also see Using FormData objects for more examples.