This question already has answers here:
Flask App: Update progress bar while function runs
(3 answers)
Closed 1 year ago.
Just want to insert a progress bar in my html page. It should load from a for in my app.py. That's what I did so far...
app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/progress')
def ajax_index():
for i in range(500):
print("%d" % i)
# I want to load this in a progress bar
if __name__ == "__main__":
app.run(debug=True)
I'm using a bootstrap progress-bar from w3schools in my code
index.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function () {
$("#content").load("/progress");
});
</script>
</head>
<body>
<div class="container">
<h2>Progress Bar With Label</h2>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100" style="width:0%"></div>
</div>
</div>
</body>
</html>
Any help, please?
this is pretty simple: poll your api and update the progress bar width and valuenow until finished:
var interval = setInterval(update_progress, 1000);
function update_progress() {
$.get('/progress').done(function(n){
n = n / 5; // percent value
if (n == 100) {
clearInterval(interval);
callback(); // user defined
}
$('.progress-bar').animate({'width': n +'%'}).attr('aria-valuenow', n);
}).fail(function() {
clearInterval(interval);
displayerror(); // user defined
});
}
Related
I'm building a simple image navigator application in Python using Flask. I want to have forward and backward buttons to navigate through all the images in the static folder. So far, I've a single button which displays the image without refreshing the page. How can I navigate through the directory using buttons?
app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def hello():
return render_template('upload.html')
#app.route("/getimage")
def get_img():
return "00621.jpg"
if __name__ == '__main__':
app.run()
upload.html
<!DOCTYPE html>
<html lang="en">
<style>
img {
max-width: 100%;
max-height: 100%;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#retrieve').click(function(){
$.ajax({
url: "{{ url_for ('get_img') }}",
type : 'POST',
contentType: 'application/json;charset=UTF-8',
data : {'data':{{}}}
success: function(response) {
$("#myimg").attr('src', 'static/' + response);
},
error: function(xhr) {
//Do Something to handle error
}
});
});
});
</script>
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Image Annotator</h1>
</div>
<button type='button' id ='retrieve'>Submit</button>
<img src="" id="myimg" />
</div>
</div>
</body>
</html>
I have reconstructed some of your code to achieve the answer. Please be aware that I've switched things from Jquery to JS.
New HTML Page:
<!DOCTYPE html>
<html lang="en">
<style>
img {
max-width: 100%;
max-height: 100%;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Image Annotator</h1>
</div>
<button type='button' onclick="oclick()" id='retrieve'>Submit</button>
<button onclick="action(2)" type="button">Backward</button><button onclick="action(1)" type="button">Forward</button>
<image src="" id="myimg"></image>
</div>
</div>
<script>
var imgap = 0
function oclick(){
var getInitialImage = new XMLHttpRequest();
getInitialImage.open("GET", "/getimage");
getInitialImage.onreadystatechange = function (){
if (this.readyState == 4 && this.status == 200){
document.getElementById("myimg").setAttribute("src", "/image/" + this.responseText);
}
}
getInitialImage.send();
}
function action(ac){
if (ac == 1){
imgap += 1
var getnextimagedetails = new XMLHttpRequest();
getnextimagedetails.open("GET", "/getimage?num=" + imgap.toString());
getnextimagedetails.onreadystatechange = function (){
if (this.readyState == 4 && this.status == 200){
document.getElementById("myimg").setAttribute("src", "/image/" + this.responseText);
}
}
getnextimagedetails.send();
}
if (ac == 2){
imgap += -1
var getlastimagedetails = new XMLHttpRequest();
getlastimagedetails.open("GET", "/getimage?num=" + imgap.toString());
getlastimagedetails.onreadystatechange = function (){
if (this.readyState == 4 && this.status == 200){
document.getElementById("myimg").setAttribute("src", "/image/" + this.responseText);
}
}
getlastimagedetails.send();
}
}
</script>
</body>
</html>
New Flask Document:
from flask import Flask, send_from_directory, request
import os
app = Flask(__name__)
#app.route("/")
def hello():
return send_from_directory('', 'upload.html')
#app.route("/image/<path:path>")
def image(path):
print(path)
if (path.endswith(".jpg") or path.endswith(".png") or path.endswith(".bmp") or path.endswith(".jpeg")):
return send_from_directory("", path)
return "", 500
#app.route("/getimage")
def get_img():
print(request.args.get("num"))
if (request.args.get("num") != None):
dirfiles = os.listdir()
presentedstr = []
for string in dirfiles:
if (string.endswith(".jpg") or string.endswith(".svg") or string.endswith(".bmp") or string.endswith(".jpeg") or string.endswith(".png")):
presentedstr.append(string)
presentedstr.index("00621.jpg")
return presentedstr[presentedstr.index("00621.jpg") + int(request.args.get("num"))]
else:
return "00621.jpg"
if __name__ == '__main__':
app.run()
How this implementation works, is the button will send out a request to the server for what the next image or item is, before making another request for the actual next image itself. It will search the same directory.
I am trying to run a code but one part is not working, where I need to pass the value from a slider. I can see the value in html page but I can not pass it to inputRange() where I need to run some commands.
I've tried to isolate only the code which work with slider. Could you please let me know how can I pass the slider value to val_slide? Thanks.
Code:
from bottle import route, run, template
IP_ADDRESS = '192.168.0.80'
PORT = 8080
#route('/')
def hello():
return '<b>Test</b>'
#route('/remote')
def remote():
return '''<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css">
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>
<script>
$(document).ready(function() {
$('#inputRange').on('change mouseup', function(){
var val_slide ='inputRange';
$.ajax({
url: '/remote/inputRange',
type: 'GET',
data: {command:val_slide},
});
});
});
</script>
<style></style>
</head>
<body>
<div data-role="page">
<div data-role="main" class="ui-content">
<form>
<div style="text-align:center">
<label for="switch">Test</label>
<div class="slidecontainer">
<input id="inputRange" type="range" min="0" max="100" step="1" value="20" class="slider" name='data'>
<output name="inputRange"/output>
</div>
</form>
</div>
</div>
</body>
</html>'''
#route('/remote/inputRange')
def inputRange():
print val_slide
# use val_slide value
return 'inputRange'
try:
run(host = IP_ADDRESS, port= PORT)
except(KeyboardInterrupt):
print('Done!')
quit()
To access query parameters from GET request you should import request and use request.query to access to values by name:
from bottle import route, request
#route('/remote/inputRange')
def inputRange():
val_slide = request.query.command
print(val_slide)
return val_slide
I'm not big specialist in JavaScript, but as far as I know, to send actual value (not just static text) you need to replace val_slide static text assignment with reading of value:
var val_slide = this.value;
I'm trying to implement server push in my Flask project following this tutorial.
I've set it all up with no errors, however when I go to the /stream page, Firefox recognizes it as a file and tries to download it. In Safari it just prints out the data sent. I tried adapting the code to a simpler implementation, where a thread just yields some data each second, however it produced the same results.
My goal is for each time a python script reaches a point in a loop, it will update a progress bar on the web interface.
Any help with this would be great. Thanks.
Edit:
app.py
from flask import Flask, render_template, request, Response
app = Flask(__name__)
def event_stream():
event = "Hello!"
yield 'data: %s\n\n' % event
#app.route('/stream')
def stream():
return Response(event_stream(), mimetype="text/event-stream")
if __name__ == "__main__":
app.debug = True
app.run(threaded=True)
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
var source = new EventSource('/stream');
source.onmessage = function (event) {
alert(event.data);
};
</script>
</head>
<body>
<p>Stream page</p>
</body>
</html>
EDIT
I've uploaded my sample application to my Github. Check it out here: https://github.com/djdmorrison/flask-progress-example
I've worked it out, but for anyone else who gets the same problem:
The index.html page never actually loads, as it's never called in app.py. The way to do it is by going to a separate route, /page for example, and then returning send_file('index/html'). This will load the index page, create the EventSource linked to /stream, which will then start the stream method in app.py and yield the correct data.
Example which creates a progress bar by increasing x every 0.2 seconds and displaying it on the webpage:
app.py
#app.route('/page')
def get_page():
return send_file('templates/progress.html')
#app.route('/progress')
def progress():
def generate():
x = 0
while x < 100:
print x
x = x + 10
time.sleep(0.2)
yield "data:" + str(x) + "\n\n"
return Response(generate(), mimetype= 'text/event-stream')
progress.html
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script>
var source = new EventSource("/progress");
source.onmessage = function(event) {
$('.progress-bar').css('width', event.data+'%').attr('aria-valuenow', event.data);
}
</script>
</head>
<body>
<div class="progress" style="width: 50%; margin: 50px;">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
</div>
</body>
</html>
I'm trying to implement server push in my Flask project following this tutorial.
I've set it all up with no errors, however when I go to the /stream page, Firefox recognizes it as a file and tries to download it. In Safari it just prints out the data sent. I tried adapting the code to a simpler implementation, where a thread just yields some data each second, however it produced the same results.
My goal is for each time a python script reaches a point in a loop, it will update a progress bar on the web interface.
Any help with this would be great. Thanks.
Edit:
app.py
from flask import Flask, render_template, request, Response
app = Flask(__name__)
def event_stream():
event = "Hello!"
yield 'data: %s\n\n' % event
#app.route('/stream')
def stream():
return Response(event_stream(), mimetype="text/event-stream")
if __name__ == "__main__":
app.debug = True
app.run(threaded=True)
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
var source = new EventSource('/stream');
source.onmessage = function (event) {
alert(event.data);
};
</script>
</head>
<body>
<p>Stream page</p>
</body>
</html>
EDIT
I've uploaded my sample application to my Github. Check it out here: https://github.com/djdmorrison/flask-progress-example
I've worked it out, but for anyone else who gets the same problem:
The index.html page never actually loads, as it's never called in app.py. The way to do it is by going to a separate route, /page for example, and then returning send_file('index/html'). This will load the index page, create the EventSource linked to /stream, which will then start the stream method in app.py and yield the correct data.
Example which creates a progress bar by increasing x every 0.2 seconds and displaying it on the webpage:
app.py
#app.route('/page')
def get_page():
return send_file('templates/progress.html')
#app.route('/progress')
def progress():
def generate():
x = 0
while x < 100:
print x
x = x + 10
time.sleep(0.2)
yield "data:" + str(x) + "\n\n"
return Response(generate(), mimetype= 'text/event-stream')
progress.html
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script>
var source = new EventSource("/progress");
source.onmessage = function(event) {
$('.progress-bar').css('width', event.data+'%').attr('aria-valuenow', event.data);
}
</script>
</head>
<body>
<div class="progress" style="width: 50%; margin: 50px;">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
</div>
</body>
</html>
I am trying to implement the same stack overflow text-area with syntax highlighting in Python and have come this far but i am not able to get it working.
app.py
from flask import Flask, render_template, request
import preview
app = Flask(__name__)
#app.route('/',methods=['GET','POST'])
def index():
if request.method == 'POST':
markdown_content = request.args.get['wdd-input']
post_preview = preview.markdown(markdown_content['data'])
return render_template('test.html', result=post_preview)
if request.method == 'GET':
return render_template('demo.html')
if __name__ == '__main__':
app.run()
preview is something which does syntax highlighting and its based upon Pygments.
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>PageDown Demo Page</title>
<link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/static/css/highlighting.css">
<link rel="stylesheet" type="text/css" href="/static/css/demo.css" />
<script type="text/javascript" src="/static/js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/static/js/hycus-textarea.js"></script>
<script type="text/javascript" src="/static/js/Markdown.Editor.js"></script>
<script type="text/javascript">
(function (m) {
m(document).ready(function () {
m('textarea.wmd-input').TextAreaResizer();
});
})(jQuery);
</script>
</head>
<body>
<div class="container">
<div id="pagedwon">
<div id="tabnav">
<ul class="nav nav-tabs" id="markdown_tab" style="padding: 0 10px; margin-bottom: 10px;">
<li class="active">Edit</li>
<li>Preview</li>
</ul>
</div>
<div class="tab-content">
<div class="tab-pane active" id="edit">
<div class="wmd-panel">
<div id="wmd-button-bar"></div>
<textarea class="wmd-input" id="wmd-input" rows="10" name="text-input">
This is the *pagedown* editor.
------------------------------
**Note**: Just plain **Markdown**, except that the input is sanitized: **HTML** is not allowed.
</textarea>
</div>
<script type="text/javascript">
(function () {
var pagedown_editor = new Markdown.Editor();
pagedown_editor.run();
})();
</script>
<script type="text/javascript">
(function (m) {
m("#markdown_tab a").click(function () {
if (m(this).html() == "Preview"){
var markdown_content = m("#wmd-input").val();
if (!markdown_content) {
m("div#markdownpreview").html("Empty Markdown Content.");
} else {
content_to_preview = {
"data": markdown_content
}
m.post("/", content_to_preview)
.success( function(preview_content){
if (preview_content == 'None'){
m("div#markdownpreview").html("No content received.");
} else {
m("div#markdownpreview").html(preview_content);
}
})
.error( function () {
m("div#markdownpreview").html("Sorry, error occurred. Please retry.");
});
}
}
});
})(jQuery);
</script>
</div>
<div class="tab-pane markdown-body" id="markdownpreview">
Loding preview content ...
</div>
</div>
</div>
</div>
</body>
</html>
This is log from the console:
127.0.0.1 - - [26/Jun/2014 20:25:01] "POST / HTTP/1.1" 500 -
How to get it working, please help. I am new to Flask.
First, request.args is for query string parameters, but you are sending over data via POST. You should be using request.form instead.
Second, MultiDict.get is a function, and does not support the __getitem__ protocol (which is the cause of your 500 error).
Third, as #Doobeh points out in the comments, you are sending the data over under the key data, but you are trying to access it via the key "wdd-input" - this will result in a BadRequest error.
Finally, the value extracted from request.form will be a string (which does not support strings as __getitem__ values) - and you don't need it anyway, as you already have the entire string.
A re-worked version of your POST portion:
if request.method == 'POST':
markdown_content = request.form.get('data', 'No content yet ...')
post_preview = preview.markdown(markdown_content)
return render_template('test.html', result=post_preview)