I have a form with a button to edit an existing record. On button click, a modal opens to update the record, including a button to delete an existing file attached to the record which, when clicked triggers an ajax call to a delete_file PHP script. If a file exists, its file name is previewed in the ‘p’ element.
The problem I’m running into is that if the user edit’s a record that didn’t contain a file, uploads a file, and then deletes it without saving the record, my existing code doesn’t work to delete the file. It’s because HTML is dynamically being generated on file upload to place the file url in a button attribute which is not available to pass to file delete.
After researching I believe the solution is event delegation. I’ve tried several recommendations but none have worked. How can I:
- add a file (with filename in "$("button").attr("data-fileurl") // this works
- after clicking ‘delete file’ button, store $("button").attr("data-fileurl") in a variable
- pass the url variable to the delete_file function
HTML:
<div id='file_upload' class='file-upload'>
<input type='file' id='file_input' style='opacity:0;' />
<p class='file_upload_text'>Click to upload file</p>
</div>
<div id='file_upload_preview' class='file-upload file-preview' style='display:none;'>
<div class='file_preview'></div>
<button id='fileurl' data-fileurl='' class='file_delete'>Delete</button>
</div>
JQuery:
jQuery(document).ready(function($) {
var filesToUpload = [];
var fileUrlDelegated = "";
$('#file_input').on('change', function(e) {
var files = e.target.files[0];
filesToUpload.push(files);
prepareUpload(filesToUpload);
$(".file_delete").on('click', function(e) {
e.preventDefault();
$(document.body).on('change', "button [data-fileurl]", function (event) { // not working
fileUrlDelegated = $(event.target).attr("data-fileurl");
});
delete_file(fileUrlDelegated);
});
});
function prepareUpload(file) { // upload file; dynamic HTML generated after an ajax call; this works
var parent = $("#file_input").parent();
var previewID = parent.attr("id") + "_preview";
var previewParent = $("#"+previewID);
previewParent.show();
previewParent.children(".file_preview").empty().append( preview );
previewParent.children( "button" ).attr("data-fileurl", data.url );
parent.children("input").val("");
parent.hide();
}
function delete_file (file_url) { // works as long as url is provided
$(".file_preview").text("");
$("button").attr("data-fileurl", "");
$("#file_upload_preview").hide();
$("#file_upload").show();
var data = new FormData();
data.append("fileurl", file_url);
$.ajax({
url: general_globals.ajaxurl,
type: 'POST',
data: data,
processData: false,
contentType: false,
cache: false,
dataType: 'json'
});
}
2
Answers
Try using the FileReader API instead of relying on AJAX calls. You can make a method like
This way, you don’t touch your database until the user saves the record, so your problem is solved.
You just need to rewrite your logic and rest of
code
look fine to whats its doing. Todelete
file and pass thedata-fileurl
– You can simply check if the file URL exist at all or not which was generated by prepare Upload.Also, to get the data attributes we can simply use .data method and write
.data('fileurl')
injQuery
to get the buttonfileurl
and then pass that to our deletefunction
for theajax
to be call forbackend
.To get the correct
fileURL
we can use$(this)
in our delete function which refer to the element we have clicked on which will be.file_delete
We will use
event Delegation
in your case just to be safe since HTML are dynamically created.Replace your delete file function to this: (Code tested on localhost and working)