简体   繁体   中英

How to use JQuery event delegation on element attribute change?

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'
  });
}

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
  }
});

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM