I have used the below code the image has been deleted but the thumbnail image still showing.
Dropzone.options.myDropzone = {
init: function() {
this.on("success", function(file, response) {
file.serverId = response;
});
this.on("removedfile", function(file) {
if (!file.serverId) { return; }
$.post("delete-file.php?id=" + file.serverId);
});
}
For deleting thumbnails you have to enable
addRemoveLinks: true,
and to use "removedfile" option in dropzonejs
removedfile: Called whenever a file is removed from the list. You can listen to this and delete the file from your server if you want to.
addRemoveLinks: true,
removedfile: function(file) {
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
I also added an ajax call for delete script and it looks like this:
addRemoveLinks: true,
removedfile: function(file) {
var name = file.name;
$.ajax({
type: 'POST',
url: 'delete.php',
data: "id="+name,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
It works on my side, so I hope it helps.
In addition to the best answer above - to remove spaces and replace with dashes and convert to lower case apply this js in the dropzone.js file:
name = name.replace(/\s+/g, '-').toLowerCase();
To the filename handling - I edited the dropzone.js file AND the above ajax call. This way, the client handles the file naming, and it AUTOMATICALLY gets sent to the PHP/server-side, so u don't have to redo it there, and it's URL safe pretty much.
In some instances the js changed depending on the function / naming:
dropzone.js - line 293 (approx):
node = _ref[_i];
node.textContent = this._renameFilename(file.name.replace(/\s+/g, '-').toLowerCase());
dropzone.js - line 746 (approx):
Dropzone.prototype._renameFilename = function(name) {
if (typeof this.options.renameFilename !== "function") {
return name.replace(/\s+/g, '-').toLowerCase();
}
return this.options.renameFilename(name.replace(/\s+/g, '-').toLowerCase());
};
I moved the whole removedFile section up to the top of dropzone.js like so:
autoQueue: true,
addRemoveLinks: true,
removedfile: function(file) {
var name = file.name;
name =name.replace(/\s+/g, '-').toLowerCase(); /*only spaces*/
$.ajax({
type: 'POST',
url: 'dropzone.php',
data: "id=" + name,
dataType: 'html',
success: function(data) {
$("#msg").html(data);
}
});
var _ref;
if (file.previewElement) {
if ((_ref = file.previewElement) != null) {
_ref.parentNode.removeChild(file.previewElement);
}
}
return this._updateMaxFilesReachedClass();
},
previewsContainer: null,
hiddenInputContainer: "body",
Note I also added in a message box in the html: (div id="msg"></div>) in the HTML that will allow server side error handling/deleting to post a message back to the user as well.
in dropzone.php:
if (isset($_POST['id']) {
//delete/unlink file
echo $_POST['id'] . ' deleted'; // send msg back to user
}
This is only an expansion with the working code on my side. I have 3 files, dropzone.html, dropzone.php, dropzone.js
Obviously, you would create a js function instead of repeating the code, but it suited me since the naming changes. You could pass the variables in a js function yourself to handle filename spaces/chars / etc.
Related
I'm trying to use dropzone to upload large files directly to Azure storage using a SAS(Shared Access Signature). This is documented on the Azure side here: https://learn.microsoft.com/en-us/rest/api/storageservices/Put-Block
So I have to get the blockId(A Base64 string that identifies the chunk I'm sending) and put it in the url of the request sending that chunk.
Dropzone supports chunking now so I decided to use that. Unfortunately, implementations of it are hard to find.
I can change the url in the processing event but that's per file and I can't get chunk data from it.
I can send the blockId in the form data using params but can't seem to change the url from it.
Is it possible to add the blockId to my url? Or will I have to send it to my server first and upload from there? Thanks.
$("#videoSection").dropzone({
params: function (files, xhr, chunk) {
console.log(chunk);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
//I can get the blockId from the chunk here
//this.options.url.replace("test") //doesn't work
//xhr.open(this.options.method, this.options.url.replace("test"), true); //doesn't work
return {"url": "test"}; //this returns form-data
},
url: "Create",
method: "PUT",
//headers: { "x-ms-blob-type": "BlockBlob" },
chunking: true,
chunkSize: 4000000,
forceChunking: true,
retryChunks: true,
retryChunksLimit: 3,
autoProcessQueue: false,
acceptedFiles: "video/*",
maxFiles: 1,
maxFilesize: 3000,
previewTemplate: $("#videoTemplate").html(),
dictDefaultMessage: "Drop Video Here",
init: function () {
this.on("processing", function (file) {
var blockId = 1;
#*this.options.url = "#(Config.Value.StoragePrefix)/#(user.Company.StorageName)/inspections/#Model.InspectionData.Inspection.Id/videos/"
+ file.name + "#Html.Raw(Model.SharedAccessSignature + "&comp=block&blockid=")" + blockId;*#
var progressBar = $(file.previewElement).find(".dropzoneProgressBar");
progressBar.show();
});
this.on("chunksUploaded", function (file, done) {
$.ajax({
type: "PUT",
url: "#(Config.Value.StoragePrefix)/#(user.Company.StorageName)/inspections/#Model.InspectionData.Inspection.Id/videos/"
+ file.name + "#Html.Raw(Model.SharedAccessSignature + "&comp=blocklist")",
success: function (data) {
done();
},
error: function (e) {
toastr.error(e);
console.log(e);
}
});
});
this.on("uploadprogress", function (file, progress, bytesSent) {
var progressBar = $(file.previewElement).find(".dropzoneProgressBar");
progress = bytesSent / file.size * 100;
progressBar.width(progress + "%");
});
this.on("success", function (file, response) {
var successCheckmark = $(file.previewElement).find(".dropSuccess");
successCheckmark.toggle();
var progressBar = $(file.previewElement).find(".dropzoneProgressBar");
progressBar.css("background-color", "green");
});
}
});
There is a problem with this line this.options.url.replace("test") //doesn't work. It should be this.options.url = this.options.url.replace("test", "newValue") //this should work. I am using a similar approach. The issue is that the params callback is called once XmlHttpRequest has been opened so you need to set the url for the first chunk before you start processing the file and in the params you need to set the url for the next chunk to be sent (use chunk.index + 1 for zero based indexing). I am not sure if this would work if you had parallelChunkUploads enabled - I haven't tested if the first chunk to be processed is the first one. Let me know if you need more information.
I am using the Dropzone JS plugin to upload and manage images on my server. Everything works great, but now I need to force the user to keep at least one image for the product. That means that if the users wants to change the images they need to upload a new one image before they delete the old one.
I can manage it on the server side, but I can't figure out a way to retain the thumbnail visible and notify the user they are not allowed to delete the last one. Just keeping the image on the server without telling the users whats going on will result on a bad UX.
Here is my code
$("div#myId").dropzone({
url: "/stores/sell_upload/",
maxFiles: 4,
acceptedFiles: "image/*",
addRemoveLinks: true,
renameFile: function(file) {
let newName = file.name.replace("." + file.name.split(".").pop(), "") + "-" + new Date().getTime() + "." + file.name.split(".").pop();
return newName;
},
removedfile: function(file) {
$.ajax({
type: "POST",
url: "/stores/sell_upload/",
data: {
name: file.name,
action: "delete"
}
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
});
So, Wouldn't it be easier if you validated the files in the action of the button to save? I mean, the dropzone area can be empty but you in your button action validate that it has to be at least one file in the area to be saved.
I keep getting the problem with downloaded zip file. All the time when I click on the archive it throws "Archive is either unknown format or damaged". I think the problem is with the coding (format of the content of the archive). Please help!
$.ajax({
url: '/Unloading/' + $("#radioVal:checked").val(),
type: "POST",
data: { 'dateTimeTo': $("#dateTimeTo").val(), 'dateTimeFrom': $("#dateTimeFrom").val() },
beforeSend: function() {$("#divLoading").show();},
success: function (result) {
$("#divLoading").hide();
if (result.length === 0) {
var message ="Error";
$("#dialog-message").text(message);
$("#dialog-message").dialog({
modal: true,
buttons: {
close: function() {
$(this).dialog("close");
}
}
});
} else {
var xmlstr, filename, bb;
filename = "UnloadedLeases.zip";
bb = new Blob([result], { type: "application/zip" }); // I think somewhere here is a problem with the coding
var pom = document.createElement('a');
pom.setAttribute("target", "_blank");
pom.setAttribute('href', window.URL.createObjectURL(bb));
pom.setAttribute("download", filename);
document.body.appendChild(pom);
pom.click();
document.body.removeChild(pom); //removing the element a from the page
}
},
As far as I know, $.ajax doesn't let you download binary content out of the box (it will try to decode your binary from UTF-8 and corrupt it). Either use a jQuery plugin (like jquery.binarytransport.js) or use a xhr directly (with responseType).
$.ajax({
url: '/Unloading/' + $("#radioVal:checked").val(),
type: "POST",
dataType: 'binary', // using jquery.binarytransport.js
// ...
success: function (result) {
// Default response type is blob
if (result.size === 0) { // instead of length for blobs
// ...
} else {
var bb = result; // already a blob
// ...
}
}
})
I am trying to implement Dropzone JS to help with uploading files to the server. I'm using a generic implementation of Dropzone on the client side with my html looking like this:
<form id='portfolioupload' action='PortfolioUpload.php' class='dropzone'>
<div class='fallback'>
<input name='file' type='file' />
</div>
</form>
In the server, I do some checks and, in the end, I rename the file and move it into it's final place:
$newname = substr(GetGUID(false), -7) . '.' . $ext;
move_uploaded_file($_FILES['file']['tmp_name'], PortfolioPath() . $newname)
I pass this information back using json, as suggested in Dropzone.js- How to delete files from server?:
header_status(200); // output header, error 200
echo json_encode(array("Filename" => $newname));
The code sample there looks like it adds it to an array that can be passed to the server for deletion. So close, but not quite what I'm looking for.
I then stumble on the question, how to upload and delete files from dropzone.js, and see that I can listen to the removedfile event. So I implement the code there like so:
Dropzone.options.portfolioupload = {
acceptedFiles: '.png, .jpg, .gif',
addRemoveLinks: true,
maxFiles: 25,
maxFilesize: 500000,
removedfile: function(file) {
alert('Deleting ' + file.name);
var name = file;
$.ajax({
type: 'POST',
url: 'app/assets/PortfolioUpload.php',
data: "f=delete&fn="+name,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
};
The request is sent to the server successfully except that the filename is that of the original, not the server's renamed filename.
After scouring the net today I feel like I can't figure out how to tie the two items together. For example, if I uploaded foo.jpg and rename it in the server to dk03p7b.jpg, how do I tell Dropzone that foo.jpg = dk03p7b.jpg so that when the user clicks Remove file, it's also removed in the server?
I solved this myself by, first, taking the json from the success response and saving it to the element file.previewElement.id like this:
success: function( file, response ) {
obj = JSON.parse(response);
file.previewElement.id = obj.filename;
}
Then I use that value when doing the delete ajax call in the removedfile event:
removedfile: function(file) {
var name = file.previewElement.id;
$.ajax({
type: 'POST',
url: 'deletefile.php',
data: "fn="+name,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
},
This also worked for me
// "myAwesomeDropzone" is the camelized version of the HTML element's ID
var myDropzone = new Dropzone("#myAwesomeDropzone", {
/*
* This step isn't required.
success: function(file, response) {
file.previewElement.id = response.id;
}
*/
});
myDropzone.on('removedfile', function(file) {
var id = jQuery(file.previewElement).find('.dz-filename span').html();
// directly access the removing preview element and get image name to delete it from server.
// var id = file.previewElement.id;
$.ajax({
type: 'POST',
url: '<?php echo base_url('seller/deleteImagegalleryById'); ?>',
data: {id: id, '<?php echo $this->security->get_csrf_token_name(); ?>': '<?php echo $this->security->get_csrf_hash(); ?>'},
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
});
I'm working on an image upload form which will validate if the uploaded picture contain nudity with the help of nudejs script.
If the image doesn't contain nudity it will be uploaded.
The upload and check nudity function are working great, but the problem is that i didn't find a way to link these 2 methods since the return of the check nudity function "onImageClick()" come 'undefined' so i can't check if its true or false in order to call the upload function via $.ajax.
This is the code:
$(document).ready(function (e) {
$("#uploadimage").on('submit',(function(e) {
e.preventDefault();
//return onImageClick('previewing'); //previewing is the id of the image in my html file
//if(onImageClick('previewing')) return;
var rn = onImageClick('previewing');
console.log("rn: "+rn); //always get undefined
$("#message").empty();
$('#loading').show();
$.ajax({
url: "ajax_php_file.php",
type: "POST",
data: new FormData(this),
contentType: false,
cache: false,
processData:false,
success: function(data) {
$('#loading').hide();
$("#message").html(data);
}
});
}));
// Function to preview image after validation
$(function() {
$("#file").change(function() {
$("#message").empty(); // To remove the previous error message
var file = this.files[0];
var imagefile = file.type;
var match = ["image/jpeg","image/png","image/jpg"];
if(!((imagefile==match[0]) || (imagefile==match[1]) || (imagefile==match[2]))) {
$('#previewing').attr('src','no-preview.png');
$("#message").html("<p id='error'>Please Select A valid Image File</p>"+"<h4>Note</h4>"+"<span id='error_message'>Only jpeg, jpg and png Images type allowed</span>");
return false;
}
else
{
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(this.files[0]);
}
});
});
function imageIsLoaded(e) {
$("#file").css("color","green");
$('#image_preview').css("display", "block");
$('#previewing').attr('src', e.target.result);
$('#previewing').attr('width', '250px');
$('#previewing').attr('height', '230px');
};
//check nudity function
function onImageClick(node) {
nude.load(node);
// Scan it
nude.scan(function(result){
console.log(result ? "Nudity found in " + node + "!" : "Not nude");
console.log("returned value is:",result);
return result;
});
}
});
EDIT: I edit the code based on #Amir answer where he mention an important point i didn't notice before.
Now i can fire the upload function when there is no nudity, but the image didn't uploaded even the success function in ajax call is fired:
success: function(data)
{
$('#loading').hide();
$("#message").html(data);
}
This is the new code:
$(document).ready(function (e) {
$("#uploadimage").on('submit',(function(e) {
e.preventDefault();
//call check nudity function
onImageClick('previewing');
//check nudity function
function onImageClick(node) {
nude.load(node);
// Scan it
nude.scan(function(result){
console.log(result ? "Nudity found in " + node + "!" : "Not nude");
console.log("returned value is:",result);
if(result){
alert("conatain nudity!!");
}
else{
$("#message").empty();
$('#loading').show();
$.ajax({
url: "ajax_php_file.php",
type: "POST",
data: new FormData(this),
contentType: false,
cache: false,
processData:false,
success: function(data)
{
$('#loading').hide();
$("#message").html(data);
}
});
}
});
};
}));
// Function to preview image after validation
$(function() {
$("#file").change(function() {
$("#message").empty(); // To remove the previous error message
var file = this.files[0];
var imagefile = file.type;
var match= ["image/jpeg","image/png","image/jpg"];
if(!((imagefile==match[0]) || (imagefile==match[1]) || (imagefile==match[2])))
{
$('#previewing').attr('src','no-preview.png');
$("#message").html("<p id='error'>Please Select A valid Image File</p>"+"<h4>Note</h4>"+"<span id='error_message'>Only jpeg, jpg and png Images type allowed</span>");
return false;
}
else
{
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(this.files[0]);
}
});
});
function imageIsLoaded(e) {
$("#file").css("color","green");
$('#image_preview').css("display", "block");
$('#previewing').attr('src', e.target.result);
$('#previewing').attr('width', '250px');
$('#previewing').attr('height', '230px');
};
});
nude.scan is async so you should pass a callback.
something like:
nude.scan(function (result) { /* your logic according to the result */ })
I found a solution for this, the problem was with FormData, it was returning:
TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement. That is for some reason didn't appear in chrome console but it does in Firefox.
So i added this line of code in the else statement(in case nudity not found):
var form = $('form').get(0);
this code returns a jQuery object($('form')) and pass a HTML element to FormData (get(0)).
Then in ajax request: data: new FormData(form),
Hope that this solution help other people.