Refreshing this Div using data retrieved from an ajax call

I am encountering an issue with multiple forms on my website. Each form accepts a file upload and then displays the upload status in a specific element. However, when updating one form, the status is displayed on a different form, causing confusion for users.

Is there a way to ensure that each form updates its status independently based on which form is being updated?

Below is the code I am using:

<script>
function _(el) {
  return document.getElementById(el);
}

function uploadFile(element) {
  var file = _("file1").files[0];
  alert(file.name+" | "+file.size+" | "+file.type);
  var formdata = new FormData();
  formdata.append("file1", file);
  var ajax = new XMLHttpRequest();
  var uploadValue = element.getAttribute("data-uploadValue");
  ajax.upload.addEventListener("progress", progressHandler, false);
  ajax.addEventListener("load", completeHandler, false);
  ajax.addEventListener("error", errorHandler, false);
  ajax.addEventListener("abort", abortHandler, false);
  ajax.open("POST", "/upload/" + uploadValue); //
  ajax.send(formdata);
}

function progressHandler(event) {
  _("loaded_n_total").innerHTML = "Uploaded " + event.loaded + " bytes of " + event.total;
  var percent = (event.loaded / event.total) * 100;
  _("progressBar").value = Math.round(percent);
  _("status").innerHTML = Math.round(percent) + "% uploaded... please wait";
}

function completeHandler(event) {
  _("status").innerHTML = event.target.responseText;
  _("progressBar").value = 0; //wil clear progress bar after successful upload
}

function errorHandler(event) {
  _("status").innerHTML = "Upload Failed";
}

function abortHandler(event) {
  _("status").innerHTML = "Upload Aborted";
}
</script>
<form id="upload_form" enctype="multipart/form-data" method="post">
  <div class="file has-name is-fullwidth is-info">
    <label class="file-label">
        <input class="file-input" type="file" name="file1" id="file1" data-uploadValue="{{ item[0] }}"  onchange="uploadFile(this)"><br>
        <span class="file-cta">
          <span class="file-icon">
            <i class="fa fa-upload"></i>
          </span>
          <span class="file-label">
            Choose a file…
          </span>
        </span>
        <span class="file-name">
          <div style="color:red;" id="status"></div>
          Supported file types: .png, .jpg, .jpeg and .gif
        </span>
      </label>
    <div style="display:none">
      <p id="loaded_n_total"></p>
      <progress id="progressBar" class="progress" value="0" max="100" style="width:300px;"></progress></div>
  </div>
</form>

Update 1: I have modified the JavaScript code to be more reliable.

Update 2: To address the issue, I incorporated unique identifiers for each form within the JavaScript loop corresponding to each form. This adjustment did not resolve the problem as intended.

Update 3: A potential conflict arises from having additional forms preceding the upload form, specifically containing a text area. While the provided solution works without these extra forms, it encounters complications when they are present.

Answer №1

The issue in the original poster's code lies within the getElementById method, which only returns the first element. A more effective solution is to search for elements within each form (when there are multiple forms) within a closure bound to the form. Here's an example of how this can be achieved:
Update

I have noticed that another form preceding each upload form contains a text area, causing some complications. Alex Kudryashev's solution works without these additional forms but not with them.

Refer to the updates in the following code snippet:

<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script>
        document.addEventListener("DOMContentLoaded", function () {
            for (var i = 0, form; form = document.forms[i]; ++i) {//iterate throu forms
                initForm(form);
            }
        });
        function initForm(frm) {
            //find elements of interest inside the form
            var fileUpload = frm.file1;//get by 'name' attribute inside the form
            var statusInfo = frm.querySelector('.status');
            var progressBar = frm.querySelector('.progress');
            var progressInfo = frm.querySelector('.loaded_n_total');

            //update. 'textarea' is in a separate form which doesn't contain 'file1'
            if (fileUpload)
               fileUpload.addEventListener('change', uploadFile);

            function uploadFile(e) {//'e' is 'change' event. It isn't used and may be ommited
                var file = this.files[0];// 'this' is fileUpload element
                //alert(file.name + " | " + file.size + " | " + file.type);
                console.log(file);
                var formdata = new FormData();
                formdata.append("file1", file, file.name);

                //update. A form with fileUpload contains other elements
                for (var i = 0, el; el = this.form.elements[i]; ++i) {
                    if (el !== this)
                        formdata.append(el.name, el.value);
                }

                statusInfo.innerHTML = 'prepare upload';
                var ajax = new XMLHttpRequest();
                var uploadValue = this.getAttribute("data-uploadValue");
                ajax.upload.addEventListener("progress", progressHandler, false);
                ajax.addEventListener("load", completeHandler, false);
                ajax.addEventListener("error", errorHandler, false);
                ajax.addEventListener("abort", abortHandler, false);
                ajax.open("POST", "/upload/" + uploadValue); //
                ajax.send(formdata);
            }
            function progressHandler(event) {
                progressInfo.innerHTML = "Uploaded " + event.loaded + " bytes of " + event.total;
                var percent = (event.loaded / event.total) * 100;
                progressBar.value = Math.round(percent);
                statusInfo.innerHTML = Math.round(percent) + "% uploaded... please wait";
            }

            function completeHandler(event) {
                statusInfo.innerHTML = event.target.responseText;
                progressBar.value = 0; //wil clear progress bar after successful upload
            }

            function errorHandler(event) {
                statusInfo.innerHTML = "Upload Failed";
            }

            function abortHandler(event) {
                statusInfo.innerHTML = "Upload Aborted";
            }
        }//initForm

    </script>
</head>
<body>
    <form enctype="multipart/form-data" method="post">
        <div class="file has-name is-fullwidth is-info">
            <label class="file-label">
                <input class="file-input" type="file" name="file1" data-uploadValue="form/1"><br>
                <span class="file-cta">
                    <span class="file-icon">
                        <i class="fa fa-upload"></i>
                    </span>
                    <span class="file-label">
                        Choose a file…
                    </span>
                </span>
                <div class="file-name">
                    <div style="color:red;" class="status"></div>
                    Supported file types: .png, .jpg, .jpeg, and .gif
                </div>
            </label>
            <div style="display:none">
                <p class="loaded_n_total"></p>
                <progress class="progress" value="0" max="100" style="width:300px;"></progress>
            </div>
        </div>
    </form>
    <form enctype="multipart/form-data" method="post">
        <div class="file has-name is-fullwidth is-info">
            <label class="file-label">
                <input class="file-input" type="file" name="file1" data-uploadValue="form/2"
                       ><br>
                <span class="file-cta">
                    <span class="file-icon">
                        <i class="fa fa-upload"></i>
                    </span>
                    <span class="file-label">
                        Choose a file…
                    </span>
                </span>
                <div class="file-name">
                    <div style="color:red;" class="status"></div>
                    Supported file types: .png, .jpg, .jpeg, and .gif
                </div>
            </label>
            <div style="display:none">
                <p class="loaded_n_total"></p>
                <progress class="progress" value="0" max="100" style="width:300px;"></progress>
            </div>
        </div>
    </form>
</body>
</html>

Answer №2

It is important to avoid defining the same id multiple times on a webpage. This can cause issues with jQuery code targeting the id, as the DOM will prioritize the first occurrence it finds in the document hierarchy. Therefore, only the first instance of a particular id will be referenced.

To address this issue, consider changing the attribute from id="status" to a class, such as class="status". Then, reference this class within your ajax function in relation to the submitted form. This approach will ensure that the status is only appended to the relevant element. See the example code below:

$('#uploadform').ajaxForm({
    beforeSend: function() {
        $(this).find('.status').empty();
        var percentVal = '0%';
        bar.width(percentVal);
        percent.html(percentVal);
    },
    uploadProgress: function(event, position, total, percentComplete) {
        var percentVal = percentComplete + '%';
        bar.width(percentVal);
        percent.html(percentVal);
        //console.log(percentVal, position, total);
    },
    success: function() {
        var percentVal = '100%';
        bar.width(percentVal);
        percent.html(percentVal);
    },
    complete: function(xhr) {
        $(this).find('.status').html(xhr.responseText);
    }
});

Answer №3

Let's examine this specific section:

    uploadProgress: function(event, position, total, percentComplete) {
        var percentVal = percentComplete + '%';
        bar.width(percentVal)
        percent.html(percentVal);
        //console.log(percentVal, position, total);
    },

In the code provided, references are made to 'bar' and 'percent' as follows:

var bar = $('.bar');
var percent = $('.percent');
var status = $('#status');

The issue here is that any updates made to 'status' will only affect the first element, while 'bar' and 'percent' for form elements 1 through n will always display the same updated value. This happens due to each variable being bound by the DOM. To resolve this, let's make some adjustments to your code for a more efficient solution:

<script>
    (function() {

        var forms = $(".some-upload-forms");

        for (var i = 0; i < forms.length; i++){
            initializeFormEvents(forms[i]);
        }

        function initializeFormEvents(form){
            var bar = form.find('.bar');
            var percent = form.find('.percent');
            var status = form.find('#status');
            var uploadForm = form.find("#uploadform");

            uploadForm.ajaxForm({
                beforeSend: function() {
                    status.empty();
                    var percentVal = '0%';
                    bar.width(percentVal)
                    percent.html(percentVal);
                },
                uploadProgress: function(event, position, total, percentComplete) {
                    var percentVal = percentComplete + '%';
                    bar.width(percentVal)
                    percent.html(percentVal);
                    //console.log(percentVal, position, total);
                },
                success: function() {
                    var percentVal = '100%';
                    bar.width(percentVal)
                    percent.html(percentVal);
                },
                complete: function(xhr) {
                    status.html(xhr.responseText);
                }
            })
        }
    })();


    </script>

Here is your modified HTML structure:

<div class='some-upload-forms">
    <form id="uploadform" enctype="multipart/form-data" method="post">
        <div class="file has-name is-fullwidth is-info">
          <label class="file-label">
            <input class="file-input" type="file" name="file1" id="file1" data-uploadValue="{{ item[0] }}"  onchange="uploadFile(this)"><br>
            <span class="file-cta">
              <span class="file-icon">
                <i class="fa fa-upload"></i>
              </span>
              <span class="file-label">
                Choose a file…
              </span>
            </span>
            <span class="file-name">
              <div style="color:red;" id="status"></div>
              Supported file types: .png, .jpg, .jpeg and .gif
            </span>
          </label>
          <div style="display:none"><p id="loaded_n_total"></p>
          <progress id="progressBar" class="progress" value="0" max="100" style="width:300px;"></progress></div>
        </div>
    </form>
</div>

You can duplicate these forms on the page starting from ; ensure each form is correctly duplicated.

Answer №4

To ensure your uploader is in a valid repeatable form, you must update the ids of each form to be unique and functional independently.

I'll break down the process into two steps. The first step involves converting your invalid HTML code to valid HTML:

function runner(index) {
  var form = document.getElementById('upload_form');
  if (!form) return false;
  form.id = 'upload_form-' + index;
  var children = document.querySelectorAll('#upload_form-' + index + ' *');
  for (i = 0; i < children.length; i++) {
    if (children[i].id) {
      children[i].id = children[i].id + '-' + index;
    }
  }
  return true;
}

var index = 0;

while (runner(index)) {
  index++;
}

This script iterates through all forms with the id upload_form, appending an index to make them unique along with their child elements.

Here's a quick test:

Execute the script and inspect the forms to see the unique indexes assigned to them and their child elements.


The second step involves ensuring your current code references and uses the parent form's id correctly to select elements inside it. To achieve this, I fetch the parent form's index based on the input being used and pass it as a parameter to subsequent functions using closures.

function _(el, index) {
  return document.getElementById(el + '-' + index);
}

function uploadFile(element) {
  var formId = element.closest('form').id,
    index = formId.split('-')[formId.split('-').length - 1],
    file = _("file1", index).files[0];
  alert(file.name + " | " + file.size + " | " + file.type);
  var formdata = new FormData();
  formdata.append("file1", file);
  var ajax = new XMLHttpRequest();
  // Additional event listeners
}

// Other supporting functions

Note: A minor adjustment was made to handle cases where event.total could be zero causing issues with the percentage calculation. If this doesn't apply to your scenario, feel free to revert back.

Upon testing, the functionality appears to work. Any errors encountered are likely due to restrictions on POST requests within this environment. If you encounter any difficulties, let me know for further assistance.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is using window.postMessage(...) a viable option for facilitating cross domain file uploads?

I'm wondering if there is a way to achieve cross domain file upload using window.postMessage(...) or any other technique. Can anyone help with this? ...

The function persists in outputting a true result, despite the fact that it is expected to output

Currently, I am working on a NextJS project where I have a client-side form. I've been attempting to implement validation for the form by creating a separate function called validateForm(). However, no matter what input is provided, the function alway ...

Hover effects can be applied to CSS tabs

There seems to be a CSS issue on Chrome where the background image is not hiding when clicking on next tabs. I have used the following code: .paymentBank ::after { content: " "; } You can view the live code [here][1] and I have also attached a scree ...

Animating links with multi-line effects on :before.orEnhancing

As per the given query, I have a code snippet Is there any way to apply this effect to multiple lines of text instead of just one line? Currently, the effect only appears on one of two text lines (as shown in the example). :root { --00a3a3: #00a3a3; ...

CSS button with folded corner illusion and dynamic transitions

I have been using the code provided below to create a folded corner effect on a button, but I am having trouble with the white background that appears in the upper left corner of the button. Is there a class I can use to make this transparent so that the y ...

Ant Design radio group buttons are currently dysfunctional

I'm having some trouble with radio group buttons. Can anyone assist me with this issue? (your help is greatly appreciated) Current Problem: Radio Group buttons are unclickable. Not sure where the issue lies! Technologies Used: React hooks, styled-co ...

retrieve the value from the angularfire database list subscription

I need help with calculating the total sum of 'amount' values in my 'expenses' list. Take a look at my database: https://i.sstatic.net/lN3OQ.gif Although the log inside the subscribe function correctly shows a total of 1700, I'm ...

Quasar Troubles with Touch Swipe Gestures

I'm facing two issues, the first being that the directives are not functioning as expected. For example, I've implemented a swipe only to the right: <div class="q-pa-md row justify-center"> <q-card v-touch-swipe. ...

Using jquery ujs to stop a form submission if the field is empty

I'm facing an issue with a form that submits using data-remote => true. The form consists of a single field, a textarea. My goal is to block the submission of the form if the textarea's length is 0 and only permit form submission if the lengt ...

"Using JavaScript to find and manipulate objects within an array by either removing them or adding

I'm struggling to manipulate an array by either removing or adding an object based on its existence. I've attempted using both a for if loop and forEach loop but haven't been successful. Here's my current approach: // Object in ...

Issue encountered while executing tasks in the Gruntfile.js file

Having trouble with Grunt concatenating my CSS files into one named production.css Below is the output I received from the command prompt: C:\Users\josha\Desktop\Repos\AJAX Project - Grunt Test>grunt C:\Users\josha& ...

Bottom div refuses to adhere to the bottom of the page

I need help with creating a footer div that sticks to the bottom, left, and right of the page. The current footer doesn't extend all the way down and left. How can I resolve this without using "position: fixed;"? Below is the code snippet (I have rep ...

"Did you come across `item()` as one of the methods within the array

While studying the book 'JavaScript and jQuery Interactive Front-End Web Development', I came across this interesting sentence: You can create an array using a different technique called an array constructor. This involves using the new keyword ...

Does bringing in an object and utilizing it within an Array result in the initial item becoming undefined?

I am currently working on importing a few files to create an object: // otis.ts export const otisHeadline = 'Realizing the office of the future for UTC'; export const otisPreview = toCloudinaryUrl('otisPreview1.png'); export const otis ...

What is the best way to make my text scroll horizontally if the container is not wide enough?

Instead of overwhelming you with code, I'll just share a link to the types of animations I've come across so far. Although these options are close to what I'm looking for, none of them are exactly right. The one that comes closest to my vis ...

What is the best way to place a child on top of a different parent in the stack?

There is a collection of figure tags, each with an expandable figcaption. Inside each figure, there is a clickable div that reveals the figcaption when clicked. However, the visible figcaption only overlaps the figure it belongs to and not others. Is there ...

Utilize ZLIB and Node.js to create a compressed zip archive of a folder's contents

I need to compress all the files in a directory into a single ZIP file. Currently, I am using this code snippet: var fs = require('fs'); var tar = require('tar'); var zlib = require('zlib'); var path = require('path&apo ...

Exploring the use of asynchronous data retrieval with jQuery and JSON within MVC 2.0

Attempting to retrieve server-side data using jQuery's getJSON method has hit a snag. The URL specified in the getJSON call is being reached, but the expected result is not being returned to the browser upon postback. There are suspicions that the iss ...

Updating a nested subarray using Node.js with the MongoDB API

I am currently in the process of developing a backend API using Node.js/Express and MongoDB for managing student records. I am facing difficulty with updating a sub-field within the data structure. Below is the code snippet from my Student.js file located ...

Ways to determine the position of elements when they are centered using `margin:auto`

Is there a more efficient way to determine the position of an element that is centered using CSS margin:auto? Take a look at this fiddle: https://jsfiddle.net/vaxobasilidze/jhyfgusn/1/ If you click on the element with the red border, it should alert you ...