skip to Main Content

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:

  1. add a file (with filename in "$("button").attr("data-fileurl") // this works
  2. after clicking ‘delete file’ button, store $("button").attr("data-fileurl") in a variable
  3. 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


  1. Try using the FileReader API instead of relying on AJAX calls. You can make a method like

    function readURL() {
      var input = grab your input here;
      if (input.files && input.files[0]) {
        var reader = new FileReader();
        reader.onload = function(e) {
          $('#preview').attr('src', e.target.result);
         }
         reader.readAsDataURL(input.files[0]);
       }
    };
    

    This way, you don’t touch your database until the user saves the record, so your problem is solved.

    Login or Signup to reply.
  2. You just need to rewrite your logic and rest of code look fine to whats its doing. To delete file and pass the data-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') in jQuery to get the button fileurl and then pass that to our delete function for the ajax to be call for backend.

    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)

    //Delete file
    $(document).on('click', '.file_delete', function(e) {
      e.preventDefault();
      //Get the file URL
      var fileURL = $(this).data('fileurl')
      //Check if file URL exist - then call delete else do not anything
      if (fileURL != '') {
        //Call delete function
        delete_file(fileURL);
      } else {
        return false
      }
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search