1

I have a file uploader on my website and I’m trying to keep an accurate count of the files uploaded, and display that number in an input using JavaScript / jQuery. Find a live version of an identical form Here

Here’s my HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta name="generator" content=
  "HTML Tidy for Linux (vers 25 March 2009), see www.w3.org" />

  <title></title>
</head>

<body>
  <div>
<form action="/?gf_page=preview&amp;id=2" enctype="multipart/form-data" method=
"post">
  <div>
    <h3>Samples</h3>
  </div>

  <div>
    <ul>
      <li>
        <label for="input_2_17">Upload*</label>

        <div>
          <input name="files" type="file" data-id="17" data-limit="50"
          data-max_upload_size="512" data-allowed_extensions="jpg,png,gif"
          aria-required="true" aria-invalid="false" /><input name="input_17" type=
          "hidden" value="" aria-required="true" />
        </div>

        <div>
          <p>Upload your files</p>
        </div>
      </li>

      <li>
        <label for="input_2_1">Paper Type*</label>

        <div>
          <select name="input_1" aria-required="true" aria-invalid="false">
            <option selected="selected" value="">
              Choose a paper or canvas type
            </option>

            <option value="Matte Paper|5">
              Paper 1
            </option>

            <option value="Gloss Paper|5">
              Paper 2
            </option>

            <option value="Matte Canvas|5">
              Paper 2
            </option>

            <option value="Gloss Canvas|5">
              Paper 3
            </option>
          </select>
        </div>

        <div>
          Choose paper type.
        </div>
      </li>

      <li>
        <label for="input_2_12">Quantity*</label>

        <div>
          <input name="input_12" type="text" value="" aria-required="true"
          aria-invalid="false" aria-describedby="gfield_description_2_12" />
        </div>

        <div>
          The quantity is calculated automatically based on how many images you have
          uploaded.
        </div>
      </li>

      <li>
        <label for="input_2_27">Total</label>

        <div>
          <input name="input_27" readonly="readonly" type="text" value=""
          aria-invalid="false" />
        </div>
      </li>

      <li>
        <label for="input_2_28">Email</label>

        <div>
          <input name="input_28" type="text" value="" />
        </div>

        <div>
          This field is for validation purposes and should be left unchanged.
        </div>
      </li>
    </ul>
  </div>

  <div>
    <input type="submit" value="Submit" /><input name="is_submit_2" type="hidden"
    value="1" /><input name="gform_submit" type="hidden" value="2" /><input name=
    "gform_unique_id" type="hidden" value="" /><input name="state_2" type="hidden"
    value=
    "123" /><input name="gform_target_page_number_2"
    type="hidden" value="0" /><input name="gform_source_page_number_2" type="hidden"
    value="1" /><input name="gform_field_values" type="hidden" value="" />
  </div>
</form>
  </div>
</body>
</html>

When a file is uploaded, it gets added as a <li class="fileuploader-item"></li> within <ul class="fileuploader-items-list">. If it's deleted, it's removed from <ul class="fileuploader-items-list">

Here's my JavaScript so far:

$(document).on('change', 'input', function() {
var uploadcount = $('.fileuploader-item').length;
document.getElementById("input_2_12").value = uploadcount;
});

This counts the uploaded files and shows that number in my input.

However, you can also delete files you've uploaded to the form. If a file is deleted, the number in the input doesn't decrease. Would anyone show me how to keep an accurate count of every <li class="fileuploader-item"></li> within <ul class="fileuploader-items-list">?

Siwap
  • 63
  • 8
  • 1
    Is there an element that you put a listener on to decrement the `uploadcount`? – R.A. Lucas Jul 24 '20 at 16:29
  • I'm not really sure, the user clicks on an 'x' overlay to delete the upload, then they confirm by clicking 'yes' on an alert box. I've managed to find a live version to better explain: https://wordpress-224605-1036693.cloudwaysapps.com/ Upload an image to that form, then delete it and you'll see what I mean. I'm basically trying to keep count of files uploaded to a form identical to that. – Siwap Jul 24 '20 at 17:08
  • 2
    Please include a [mre] here on Stack Overflow. When you're done with that URL and it goes down, this question will be useless to later visitors. You can use stack snippets, as you've done, but please combine the HTML and JavaScript into a single snippet so that they work together when you click Run code snippet. – Heretic Monkey Jul 24 '20 at 17:19
  • As far as I know I can't include a reproducible example as the form I'm asking about is a plugin for wordpress / woocommerce. I can't upload a small section of the code as it wont run as it should, it's all built into wordpress. – Siwap Jul 24 '20 at 18:05
  • are you sure that the count doesn't decrease ? I've see the live example and it effectively removes the li element. Maybe you use the wrong event ? – Massimo Petrus Jul 26 '20 at 22:18
  • Yes I'm sure it doesn't decrease. It only counts up, it doesn't count down when they're removed. – Siwap Jul 27 '20 at 12:15

2 Answers2

1

This is something I've encountered before. The removal from a FileList object in a input type of array of file unfortunately cannot be done as it is a readonly attribute.

Please read here Remove a FileList item from a multiple "input:file" and here How do I remove a file from the FileList for insight.

Fortunately for you, it would seem your element [name="fileuploader-list-files"] is already keeping track of these files. However, it is a hidden input field so detecting changes from it via DOM event is not possible unless it is automated. You are going to have to implement a MutationObserver. The fileCount will effectively keep track of the increment/decrements of your file uploads on-upload & on-delete.

// Select the node that will be observed for mutations
const targetNode = $(`[name="fileuploader-list-files"]`)[0];

// Options for the observer (which mutations to observe)
const config = { attributes: true };

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    for(let mutation of mutationsList) {
        if (mutation.attributeName === 'value') {
            let fileCount = (function(){
                try {
                    return JSON.parse(targetNode.value).length;
                } catch (e) {
                    return 0;
                }
            }())
            console.log(fileCount); // This is the number of files
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);
95faf8e76605e973
  • 13,643
  • 3
  • 24
  • 51
0

I see from the sample that the uploader library, when deleting an uploaded file, instead of removing the <li> element, simply makes it invisible with style="display:none" .

So the solution to have the accurate count of uploaded file could be to add the :visible selector to yours.

I.E. writing

$(document).on('change', 'input', function() {
var uploadcount = $('.fileuploader-item:visible').length;
document.getElementById("input_2_12").value = uploadcount;
});
Massimo Petrus
  • 1,881
  • 2
  • 13
  • 26
  • This doesn't work unfortunately. I tried that before posting but the count still doesn't decrease. – Siwap Jul 27 '20 at 12:11
  • look at my plunker : https://plnkr.co/edit/0Dd05aNyE46tCCg6?open=lib%2Fscript.js Can you post the code you tried ? – Massimo Petrus Jul 27 '20 at 13:12
  • I used the exact code you've used in your plunker. You're right that this does count correctly, but it requires you to reload the preview / page to get the accurate number. I think the problem is that the code needs to listen for the removal of the uploads like R.A. Lucas mentioned, then update the script. But I'm not sure what event to listen for. – Siwap Jul 27 '20 at 13:33
  • basically it requires that you' modify an input content, no reload of page. Is your input on the same page than the uploadeR ? – Massimo Petrus Jul 27 '20 at 13:37
  • why don't you listen on click for $("#gform1 button") ? – Massimo Petrus Jul 27 '20 at 13:45
  • Yes it's on the same page, I've updated by original post to include the full form HTML. I'm also including the JavaScript in the footer of my WordPress site. – Siwap Jul 27 '20 at 14:17
  • try to 1 - give an id to the form, 2 - supposing your form id is formid, listen on click for $("#formid button"), or better $("#formid).on("click","button",function(....) – Massimo Petrus Jul 27 '20 at 15:22
  • This didn’t work, I don’t think it needs to run on a button click as the uploads aren’t deleted with a button click (see the link in my original question for a working form). The script needs to run whenever there’s a change in `
      `. However, I ran the script in the answer above every second to test it, and the script above is right. It's just a case of having it run at the right time…
    – Siwap Jul 27 '20 at 16:16
  • actually in the linked page, the uploads are deleted with a button click, i.e. clicking in the white cross in the red circle un the upper right corner of the upload box (it is a button created on the fly) – Massimo Petrus Jul 27 '20 at 17:12
  • Ahh I see. I've tried adding the suggestions above but it's still not updating the count. I've uploaded the full form here [link](https://jsfiddle.net/329n7dkc/) My form actually has an ID of `gform_2`. But it's still not working with your code. – Siwap Jul 27 '20 at 18:14
  • sorry i had little time these days. I'll try today in the evening – Massimo Petrus Jul 30 '20 at 07:12