0

I'm new to Flask but I'm trying to show a 'rolling ball' while a page loads.

This link: Display a ‘loading’ message while a time consuming function is executed in Flask has been helpful but not giving me the desired results.

from flask import Flask
from flask import request
from flask import render_template
import time

app = Flask(__name__)

def long_load(typeback):
    time.sleep(5) #just simulating the waiting period
    return "You typed: %s" % typeback

@app.route('/', methods=("POST", "GET"))
def test():
    if request.method == 'GET':

        return render_template('index.html')


    elif request.method == 'POST':

        query = request.form['anything']
        outcome = long_load(query)

        return render_template("post_template.html" , display=outcome)

if __name__ == '__main__':
    app.run()

Excerpts from index.html:

<head>
<style>
div#loader {
  border: 16px solid #f3f3f3;
  border-radius: 50%;
  border-top: 16px solid #3498db;
  width: 120px;
  height: 120px;
  -webkit-animation: spin 2s linear infinite; /* Safari */
  animation: spin 2s linear infinite ;
}

/* Safari */
@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>

<script type="text/javascript">// <![CDATA[

        document.onreadystatechange = function() { 
    if (document.readyState !== "complete") { 
        document.querySelector("body").style.visibility = "hidden"; 
        document.querySelector("#loader").style.visibility = "visible"; 
    } else { 
        document.querySelector("#loader").style.display = "none"; 
        document.querySelector("body").style.visibility = "visible"; 
    } 
}; 

// ]]></script>


</head>

 <form action="." method="post">>  
       <body>
          <div class="caption">
              <table class="center">
                  <tr>
                    <td class="NEONpinktxt"> </td> 
                    <td align = "center"> <input type="submit" name="anything_submit" href="#" value="Search Results" id="loader" > </td>
                  </tr>
                     <div id="loader"></div>
               </table>
            </div>         
         </body>  
 </form>

When the page loads or refreshes, the rolling ball shows but when the 'Search Results' is clicked on, nothing happens.

Mikee
  • 783
  • 1
  • 6
  • 18

2 Answers2

1

Assuming you can get your server to return a proper document fragment

I would change

query = request.form['anything']

to

query = request.form['search']

and do this (Please note I fixed invalid HTML too)

document.onreadystatechange = function() {
  var complete = document.readyState === "complete";
  document.querySelector("body").style.visibility = complete ? "visible" : "hidden";
  document.getElementById("loader").style.display = complete ? "none" : "block";
}
document.getElementById("myForm").addEventListener("submit", function(e) {
  document.getElementById("result").style.display = "none";
  document.getElementById("loader").style.display = "block";

  e.preventDefault(); // stop submit
  let token = new FormData();
  token.append('search', document.getElementById('search').value);
  fetch(this.action, {      // form action 
      method: this.method,  // form method
      body: token
    })
    .then(response => response.text())
    .then(fromServer => {
      document.getElementById('result').innerHTML = fromServer;
      document.getElementById("result").style.display = "block";
      document.getElementById("loader").style.display = "none";

    });
})
div#loader {
  border: 16px solid #f3f3f3;
  border-radius: 50%;
  border-top: 16px solid #3498db;
  width: 120px;
  height: 120px;
  -webkit-animation: spin 2s linear infinite;
  /* Safari */
  animation: spin 2s linear infinite;
}


/* Safari */

@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
  }
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
<form id="myForm" action="getInformattionFromServer" method="post">
  <div class="caption">
    <table class="center">
      <tr>
        <td class="NEONpinktxt"><input type="text" id="search" value="" placeholder="Search something" /> </td>
        <td align="center"> <input type="submit" value="Search Results"> </td>
      </tr>
    </table>
    <div id="loader"></div>
    <div id="result"></div>
  </div>
</form>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
0

As a demo of using the loading circle for long running tasks I cobbled together a simple demo that uses Ajax to send a request to some server - the throbber is activated at the beginning of the request and runs until the long running task completes and a reply is received.

The loader is assigned the class throbber so it will play as the page loads - though it is so quick you hardly notice here.

The css was modified slightly so that the animation can be applied separately.

The original HTML was invalid so that has been corrected.

<?php
    if( $_SERVER['REQUEST_METHOD']=='POST' ){
        ob_clean();

        /* emulate long running tasks as result of XHR query */
        sleep(mt_rand(2,5));

        /* mickey mouse data for demo only */
        $_POST['time']=time();
        $_POST['ip']=$_SERVER['REMOTE_ADDR'];
        $_POST['date']=date(DATE_ATOM);
        exit(json_encode($_POST));
    }
?>
<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title>ball loader</title>
        <style>

            body{visibility:hidden;}

            div#loader {
                display:inline-block;   /* occupies less vertical space! */
                width: 120px;
                height: 120px;
            }

            .throbber{
                border: 16px solid #f3f3f3;
                border-radius: 50%;
                border-top: 16px solid #3498db;
                visibility:visible;

                -webkit-animation: spin 2s linear infinite; /* Safari */
                animation: spin 2s linear infinite ;            
            }

            @-webkit-keyframes spin {
                0% { -webkit-transform: rotate(0deg); }
                100% { -webkit-transform: rotate(360deg); }
            }
            @keyframes spin {
                0% { transform: rotate(0deg); }
                100% { transform: rotate(360deg); }
            }

        </style>
        <script>

            const ajax=function(url,params,callback){
                let xhr=new XMLHttpRequest();
                xhr.onload=function(){
                    if( this.status==200 && this.readyState==4 )callback( this.response )
                };
                xhr.onerror=function(e){
                    alert(e)
                };
                xhr.open( 'POST', url, true );
                xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
                xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
                xhr.send( params );
            };


            document.addEventListener('DOMContentLoaded',function( event ){
                const submit=document.forms.search.querySelector('input[type="submit"]');
                const input=document.forms.search.querySelector('input[ type="text" ][ name="anything" ]');
                const throbber=document.getElementById('loader');
                const out=document.querySelector('output');

                document.body.style.visibility='visible';
                throbber.classList.remove('throbber');




                submit.addEventListener('click',function(e){
                    e.preventDefault();
                    throbber.classList.add('throbber');

                    ajax( location.href, 'anything='+input.value, function(r){
                        throbber.classList.remove('throbber');
                        out.textContent=r
                    })
                });
            });
        </script>
    </head>
    <body>
        <form name='search' method='post'>
            <div class='caption'>
                <table class='center'>
                    <tr>
                        <td class='NEONpinktxt'>
                            <input type='text' name='anything' value='banana' />
                        </td> 
                        <td align='center'>
                            <input type='submit' name='anything_submit' value='Search Results' />
                        </td>
                    </tr>
                </table>

                <div id='loader' class='throbber'></div>
            </div>
        </form>
        <output></output>
    </body> 
</html>
Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • in the case where I have the input type as 'number i.e. ``` ```. Will your script still be valid? – Mikee Dec 09 '19 at 14:40
  • banana is not a number... the script should work ok if you use a number and not banana - this was only to indicate how one might set the class to animate the spinner and remove once `long running task` has completed – Professor Abronsius Dec 09 '19 at 14:43
  • oh ok, but when I do as you suggested, the results does not display on a new page as it did for my original script, it instead just displays on the search page... just trouble shooting to know what could be the issue. – Mikee Dec 09 '19 at 14:51
  • OK - I think, having read that a couple of times I understand what you mean but am unsure how you would previously had the results appear on a different page. The form action is set to `.` which I presume is the same page ( never used a `.` for form action nor have I seen it used ) so the results should be on the same page? If it was you intention to display the spinner whilst some complicated taks are computer by the server then a traditional form submission is not really going to work hence using ajax – Professor Abronsius Dec 09 '19 at 16:59