skip to Main Content

I have a simple ajax form. But Progress Bar doesn’t work on ajax form output, it freezes. I have put an example on the page so you can see it working normally.
my goal is to be able to provide the code(progress bar) here in ajax output.
https://stackoverflow.com/a/35985771/20310847

The problem here is, I believe there is a conflict/conflict between the script that checks the progress bar in the AJAX output and the ajax. It appears then, when it finished, it disappear, but no visual progression on… I wonder what I need to do to make progress bar from Ajax Output look normal without freezing?

Form.htm

<html>
<head>
    <!-- progress bar style  start -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
    .progress,
    .alert {margin: 8px;}   
    .alert {display: none;} 
    .alert-success {
        --bs-alert-color: #2c4238;
        --bs-alert-bg: #f8faff;
        --bs-alert-border-color: #768478;
        width: auto;
        max-width: max-content;
    }   
    @media screen and (max-width: 1568px) {
        .alert-success {
            width: auto;
            max-width: max-content;
        }
    }
    </style>
</head>
<!-- progress bar style  end -->

<body><br>
    <!-- form start -->
    <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
    <form class="form" action="process.php" method="POST" name="checkaddress" id="checkaddress">
    <input type="text" name="v" /> </td><input type="submit" id="submit" value="Submit" /> 
    </form>
    <!-- form end -->
    
    <!-- ajax output div is here -->
    <div class="done"></div>
    
    <!-- Here is the progress code I want to reflect in the ajax output. start -->
    <br>====================================
    <br> Example: normally this code(progress bar) works below. but it doesn't work when I call the code with ajax. freezes as above.
    <br>
    <div class='progress col-md-7 ps-0 pe-0'>
        <div class='progress-bar' role='progressbar' aria-valuenow='60' aria-valuemin='0' aria-valuemax='100' style='width: 60%;'></div>
    </div>
    <div class='alert alert-success' role='alert'>hello xxxxx</div><br>
    <!-- end -->
    
    
    <!-- form ajax script start -->
    <script>
    $('#checkaddress').on('submit', function(e) {
        // get formdata in a variable that is passed to the ajax request
        var dataToPassToAjax = $(this).serialize();
        $.ajax({
            url: "process.php",
            type: "POST",
            data: dataToPassToAjax,
            cache: false,
            success: function(resultHtml) {
                // add the returned data to the .done element
                $('.done').html(resultHtml).fadeIn('slow');
            }
        });
        // cancel the default form submit
        return false;
    });
    </script>
    <!-- end -->
    
    <!-- progress bar script start -->
    <script>
    var $progress = $('.progress');
    var $progressBar = $('.progress-bar');
    var $alert = $('.alert');
    setTimeout(function() {
        $progressBar.css('width', '10%');
        setTimeout(function() {
            $progressBar.css('width', '30%');
            setTimeout(function() {
                $progressBar.css('width', '45%');
                setTimeout(function() {
                    $progressBar.css('width', '80%');
                    setTimeout(function() {
                        $progressBar.css('width', '90%');
                        setTimeout(function() {
                            $progressBar.css('width', '95%');
                            setTimeout(function() {
                                $progressBar.css('width', '98%');
                                setTimeout(function() {
                                    $progressBar.css('width', '99%');
                                    setTimeout(function() {
                                        $progressBar.css('width', '100%');
                                        setTimeout(function() {
                                            $progress.css('display', 'none');
                                            $alert.css('display', 'block');
                                        }, 500); // WAIT 5 milliseconds
                                    }, 500); // WAIT 5 milliseconds
                                }, 800); // WAIT 5 milliseconds
                            }, 600); // WAIT 2 seconds
                        }, 700); // WAIT 1 seconds
                    }, 900);
                }, 600); // WAIT 2 seconds
            }, 400); // WAIT 1 seconds
        }, 700); // WAIT 1 seconds
    }, 800); // WAIT 1 second
    </script>
    <!-- progress bar script end -->
</body>
</html>

process.php

<?php 
$v= $_POST['v'];
echo "<div class='progress col-md-7 ps-0 pe-0'> 
<div class='progress-bar' role='progressbar' aria-valuenow='60' aria-valuemin='0' 
aria-valuemax='100' style='width: 60%;'></div>  
</div>
<div class='alert alert-success' role='alert'>hello $v</div>";
?>

2

Answers


  1. Your progress bar doesn’t work in AJAX because when the page is first loaded, there’s no progress bar to work with – it only appears after the AJAX call. Your progress bar script runs immediately when the page loads, and it tries to access .progress, .progress-bar, and .alert elements which don’t exist yet, because they’re only added to the page after the AJAX call.

    To make it work, you should include the progress bar script into the success function of the AJAX call. This way, it will be called after the new elements are added to the page.

    Here is the modified JavaScript code:

    $('#checkaddress').on('submit', function(e) {
        // get formdata in a variable that is passed to the ajax request
        var dataToPassToAjax = $(this).serialize();
        $.ajax({
            url: "process.php",
            type: "POST",
            data: dataToPassToAjax,
            cache: false,
            success: function(resultHtml) {
                // add the returned data to the .done element
                $('.done').html(resultHtml).fadeIn('slow');
                
                // run the progress bar script here
                var $progress = $('.progress');
                var $progressBar = $('.progress-bar');
                var $alert = $('.alert');
                setTimeout(function() {
                    $progressBar.css('width', '10%');
                    setTimeout(function() {
                        $progressBar.css('width', '30%');
                        setTimeout(function() {
                            $progressBar.css('width', '45%');
                            setTimeout(function() {
                                $progressBar.css('width', '80%');
                                setTimeout(function() {
                                    $progressBar.css('width', '90%');
                                    setTimeout(function() {
                                        $progressBar.css('width', '95%');
                                        setTimeout(function() {
                                            $progressBar.css('width', '98%');
                                            setTimeout(function() {
                                                $progressBar.css('width', '99%');
                                                setTimeout(function() {
                                                    $progressBar.css('width', '100%');
                                                    setTimeout(function() {
                                                        $progress.css('display', 'none');
                                                        $alert.css('display', 'block');
                                                    }, 500); // WAIT 5 milliseconds
                                                }, 500); // WAIT 5 milliseconds
                                            }, 800); // WAIT 5 milliseconds
                                        }, 600); // WAIT 2 seconds
                                    }, 700); // WAIT 1 seconds
                                }, 900);
                            }, 600); // WAIT 2 seconds
                        }, 400); // WAIT 1 seconds
                    }, 700); // WAIT 1 seconds
                }, 800); // WAIT 1 second
            }
        });
        // cancel the default form submit
        return false;
    });
    
    

    This should resolve your issue. The progress bar script now runs after the AJAX call is successful, and the new elements are added to the DOM, so it should be able to find and manipulate them as expected.

    Improvements

    The current JavaScript code involves a lot of nested setTimeout functions which make it hard to read and maintain. We can simplify it with a more dynamic and modular approach.

    Consider something like this:

    $('#checkaddress').on('submit', function(e) {
        // get formdata in a variable that is passed to the ajax request
        var dataToPassToAjax = $(this).serialize();
        $.ajax({
            url: "process.php",
            type: "POST",
            data: dataToPassToAjax,
            cache: false,
            success: function(resultHtml) {
                // add the returned data to the .done element
                $('.done').html(resultHtml).fadeIn('slow');
                
                // run the progress bar script here
                var $progress = $('.progress');
                var $progressBar = $('.progress-bar');
                var $alert = $('.alert');
                
                var width = 0;
                var increment = 10; // change the increment value to control the speed of the progress bar
                var interval = setInterval(function() {
                    width = width + increment;
                    if(width >= 100) { // when progress reaches 100, stop interval and show alert
                        clearInterval(interval);
                        $progress.css('display', 'none');
                        $alert.css('display', 'block');
                    }
                    $progressBar.css('width', width + '%');
                }, 800); // this value controls the delay between each increment
            }
        });
        // cancel the default form submit
        return false;
    });
    
    

    Here, the progress bar width increases by 10% every 800 milliseconds until it reaches 100%, at which point the interval is cleared and the alert is displayed.

    This approach is a little bit less flexible than how I would recommend, but it is easier to understand. If you want to give it a try anyway, something like this is how I would personally implement it.

    async function delay(duration) {
        return new Promise(resolve => setTimeout(resolve, duration));
    }
    
    async function updateProgressBar($progressBar, $progress, $alert, values) {
        for(let i = 0; i < values.length; i++) {
            await delay(values[i].delay);
            $progressBar.css('width', `${values[i].width}%`);
        }
        $progress.css('display', 'none');
        $alert.css('display', 'block');
    }
    
    $('#checkaddress').on('submit', function(e) {
        // get formdata in a variable that is passed to the ajax request
        var dataToPassToAjax = $(this).serialize();
        $.ajax({
            url: "process.php",
            type: "POST",
            data: dataToPassToAjax,
            cache: false,
            success: function(resultHtml) {
                // add the returned data to the .done element
                $('.done').html(resultHtml).fadeIn('slow');
                
                // run the progress bar script here
                var $progress = $('.progress');
                var $progressBar = $('.progress-bar');
                var $alert = $('.alert');
                var values = [
                    {width: 10, delay: 800},
                    {width: 30, delay: 700},
                    {width: 45, delay: 400},
                    {width: 80, delay: 600},
                    {width: 90, delay: 900},
                    {width: 95, delay: 700},
                    {width: 98, delay: 600},
                    {width: 99, delay: 800},
                    {width: 100, delay: 500}
                ];
                updateProgressBar($progressBar, $progress, $alert, values);
            }
        });
        // cancel the default form submit
        return false;
    });
    
    

    Don’t worry about it if the second example is too hard to understand. Focus on getting you code working and try to keep an eye out for code duplication. Every time you are repeating a lot of code, there’s probably a better way to do it. 🙂

    Login or Signup to reply.
    1. You forgot preventDefault() to stop the form from being submitted

      $('#checkaddress').on('submit', function(e) { 
        e.preventDefault(); // stop the submission
        progress(0); /* my code */`
        /* rest of your code */
      
    2. Your progress bar starts at 60%

    3. Here is a MUCH drier progress code

    https://jsfiddle.net/mplungjan/r1hsom07/

    let $progress = $('.progress'),
     $progressBar = $('.progress-bar'),
     $alert = $('.alert'),
     steps = [
      { percent:  '10%', delay: 800}, 
      { percent:  '30%', delay: 700}, 
      { percent:  '45%', delay: 400}, 
      { percent:  '80%', delay: 600}, 
      { percent:  '90%', delay: 900}, 
      { percent:  '95%', delay: 700}, 
      { percent:  '98%', delay: 600}, 
      { percent:  '99%', delay: 800}, 
      { percent: '100%', delay: 500}, 
      { percent: 'none', delay: 500} 
    ];
    
    
    const progress = i => {
      if (i >= steps.length) return;
      setTimeout(() => {
        if (steps[i].percent === 'none') {
          $progress.css('display', 'none');
          $alert.css('display', 'block');
        } else {
          $progressBar.css('width', steps[i].percent);
        }
        progress(i + 1);
      }, steps[i].delay);
    }
    progress(0); // Start (move this to your ajax)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
    <div class='progress col-md-7 ps-0 pe-0'>
            <div class='progress-bar' role='progressbar' aria-valuenow='60' aria-valuemin='0' aria-valuemax='100' style='width: 0%;'></div>
        </div>
        <div class='alert alert-success' role='alert'>hello xxxxx</div><br>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search