Wordpress site - How to retain event.target.files in JQuery when moving between multiple ajax calls to PHP scripts?

Viewed 134

I'm about 2 months into learning PHP and JQuery, so please bear with me. :)

I have a form with a button to add a new record. On button click, a modal opens for record entry, including a button to upload a file which, when clicked triggers an ajax call to a file upload PHP script. On submit of the modal, I use ajax to call a PHP script to save the file to the server and to save the record to the database with the url to the file saved on the server.

The problem I'm running into is that because it's a new record, the id of the record is not known at the time of calling the PHP script to upload the file to the server. I have other use cases for handling file uploads on edit record that work as expected because the id of the record is known. So, I would like to avoid having to re-arrange existing code.

After a ton of research and trying all kinds of recommendations for the past 2 weeks, I'm still not able to get this piece of functionality to work.

Where I'm at now is that the ajax call is called twice for new records. On the 1st call, since the id is empty, it just exits the function. On the 2nd call when the id is known, it fails because now the event.target.files is undefined.

One solution that I believe will work with existing code is to be able to retain event.target.files in a global variable (which I thought I was doing) so that it's still accessible for the 2nd ajax call. But, nothing I've tried has worked.

Question - how can I retain event.target.files in a global variable to be accessible for the 2nd ajax call? Or, is there a better solution that will not disrupt the already working code for record edits? Am I simply passing the event incorrectly?

Any help is greatly appreciated!

Here's relevant JS code

jQuery(document).ready(function($) {
  var files;
  $('#file_input').on('change', function() { // 1st call after clicking 'upload file' in modal
    var files = document.getElementById('file_input').files[0];
    prepareUpload(e);
  });

  $(document.body).on("click", "#submit-btn-modal", function(e) {
    e.preventDefault();
    post_record(e);
  });

});
        
function prepareUpload(e, count, new_recid) {
  if (count === 2) {
    var id = new_recid;
  } else {
      var prefix = $("#master_form_wrapper #prefix").val();
      var recid = $("#master_form_wrapper #"+prefix+"id").val();
      var id = parseInt(recid);
    }
  files = e.target.files; // errors here on 2nd call (Cannot read property 'name' of undefined)
  var data = new FormData();
  data.append("action", "file_upload");
  data.append("id", id);
  $.each(files, function(key, value) {
    data.append("file_upload", value);
    });        
  $.ajax({
    url: general_globals.ajaxurl,
    type: 'POST',
    data: data,
    cache: false,
    dataType: 'json',
    processData: false, 
    contentType: false
  });
  } 
}

function post_record(e) {
  var counter = 1;
  var post = $("#master_form_wrapper form").serialize();
  var id = $("#master_form_wrapper #"+prefix+"id").val();
  var action = 'update_record';
  $.ajax({
    url: general_globals.ajaxurl,
    data: { action : action, post : post},
    type: "post",
    success: function(response){
    if (response.search("ERROR: ") === -1) {
      record = JSON.parse(response);
      var recordID = record.record_id;
      var recid = recordID.split('_').pop();
      var counter = 2;
      prepareUpload(e, counter, recid); // 2nd call after clicking 'submit' in modal
    }
  });
}

Here's relevant HTML

<body>
  <div id='modal_cover'>
    <div id='master_form_wrapper'>
      <span class='close'><button class='close-modal'>+</button></span>
      <form name='$table' id='$table' method='post' action='' class='upload_form' enctype='multipart/form-data'>
        <input type='hidden' name='prefix' id='prefix' value='$prefix'>
        <div class='field_wrapper'>
          <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>
          <button id='submit-btn-modal' class='submit-btn-modal'>Submit</button>
        </div>
      </form>
    </div>
  </div>
</body>
1 Answers

You need to store you file which you select onChnage function in to an array. I have name that filesToUpload. Once you have selected the file it will pushed into this array.

When you click on submit-btn-modal button you will then pass this array via post_record(filesToUpload) and in this function you will get this an argument.

Once the post_record is successfully and you have received the id (recid) from the server. You can then call prepareUpload(myFiles) pass this array to your upload function along with id and the counter

In the prepare upload function we will just loop through this array and append the actual to the formData object.

I have added the notes/comments to each line of code as well for you.

Replace your code with this one below: (Code tested and working)

jQuery(document).ready(function($) {

  //array to store file
  var filesToUpload = []

  //Store File on select
  $('#file_input').on('change', function(e) { // 1st call after clicking 'upload file' in modal
    //get the file
    var files = e.target.files[0]
    //Push your file to an array
    filesToUpload.push(files);

  });

  //Upload button
  $(document.body).on("click", "#submit-btn-modal", function(e) {
    e.preventDefault();
    //send you array to upload in prepare upload
    post_record(filesToUpload);
  });
});

function prepareUpload(file, count, new_recid) {
  if (count === 2) {
    var id = new_recid;
  } else {
    //var prefix = $("#master_form_wrapper #prefix").val();
    // var recid = $("#master_form_wrapper #"+prefix+"id").val();
    //var id = parseInt(recid);
  }

  //Initialize formData
  var data = new FormData();
  data.append("action", "file_upload");
  data.append("id", id);

  //prepare each file
  for (var i = 0; i < file.length; i++) {
    data.append("file_upload", file[i]); //actual file
  }

  //Final ajax call
  $.ajax({
    url: general_globals.ajaxurl
    type: 'POST',
    data: data,
    cache: false,
    dataType: 'json',
    processData: false,
    contentType: false
  });

  //Set the array to empty again once the record is created and file uploaded
  filesToUpload = []
}

function post_record(myFiles) {

  //counter
  var counter = 1;

  //Just need these two variable for getting the ID
  var action = 'update_record';
  var post = $("#master_form_wrapper > form").serialize();

  //Ajax to get the ID
  $.ajax({
    url: general_globals.ajaxurl,
    data: {
      action: action,
      post: post
    },
    type: "post",
    success: function(response) {
      var record = JSON.parse(response);
      var recordID = record.record_id;
      var recid = recordID.split('_').pop();
      var counter = 2;

      //Call prepareUpload() and pass ID and counter and file array 
      //which we have recieved from submit button
      prepareUpload(myFiles, counter, recid);
    }
  });
}
Related