I have a web page running on Flask, the user clicks the button then gives celery a long-running program. Ajax keeps polling to check if celery has output. If celery has a result, an alert will be displayed on the web page. Now if the program running in celery is very short, the alert can be displayed occasionally. If the program running in celery takes a long time, it cannot be displayed. And now the web page seems to be: click the button - alert - refresh the page in the order.
ubuntu 16.04, Chrome
the celery parts:
#celery.task(name='app.add')
def add():
z=getLength()
return {'result':z}
#app.route('/addit', methods=['POST'])
def addit():
task = add.delay()
return jsonify({}),202,{'Location': url_for('taskstatus',task_id=task.id)}
#app.route('/status/<task_id>')
def taskstatus(task_id):
task = add.AsyncResult(task_id)
if 'result' in task.info:
response['result'] = task.info['result']
return jsonify(response)
the ajax polling parts:
<script>
function start_long_task() {
$.ajax({
type: 'POST',
url: '/addit',
success: function(data, status, request) {
status_url = request.getResponseHeader('Location');
update_progress(status_url) ;
},
error: function() {
alert('Unexpected error');
}
});
}
function update_progress(status_url) {
// send GET request to status URL
$.getJSON(status_url, function(data) {
if ('result' in data) {
// show result
alert('Result: ' + data['result']);
}
else {
setTimeout(function() {
update_progress(status_url);
}, 1000);
}
});
}
$(function() {
$('#start-bg-job').click(start_long_task);
});
</script>
The actual results may be that the webpages can show an alert when celery is done. But now it can't, please help me to fix this issue, thanks a lot!
I found that if the button that performs the polling and the button that submits the form in the flask are the same, the webpage cannot display the alert. I just created a new button, dedicated to start ajax polling, so that it is successful, the web page can display alert!
Related
I'm using Flask and JQuery to try to achieve this but pls feel free to suggest any other stack(React/Angular) if that's super easy.
I have the below AJAX in a poll.js file
$(document).ready(function(){
$('#poll').click(function(){
$('#poll').text("Working...")
$.ajax({
url: '/poll',
data: $('form').serialize(),
type: 'GET',
success: function(response){
console.log(response);
$('#poll').text("Poll")
},
error: function(error){
console.log(error);
$('#poll').text("Poll")
}
});
});
});
and my poll function in app.py is as below:
#app.route('/poll', methods=['GET'])
def poll():
call an api and return the json response
now on the UI if i click the poll button its text changes to working and it calls the function which eventually hits the API.
While this is happening, if click the home menu or navigate elsewhere on the page, i loose the AJAX call.
How do i make the ajax call continue working i.e. calling the api and updating the UI even if we try to redirect to another page or click anywhere else?
I suggest to load the data on initial page load and then refresh after set interval. to achieve this following should give you a kick start
<script type="application/javascript">
jQuery(document).ready(function($){
/* change this
$('#poll').click(function(){
$('#poll').text("Working...")
$.ajax({
url: '/poll',
data: $('form').serialize(),
type: 'GET',
success: function(response){
console.log(response);
$('#poll').text("Poll")
},
error: function(error){
console.log(error);
$('#poll').text("Poll")
}
});
});
*/
//to this it will start with page load and refresh $('#poll') every 5 seconds
var setInt = setInterval($(function(){
$('#poll').text("Working...")
$.ajax({
url:'path to script',
data: $('#form').serialize(), //your html must have form with id="form" for this
type: 'GET',
success: function(response){
console.log(response);
$('#poll').text("Poll")
},
}).fail(function(xhr,ajaxOptin,thrownError){
//console.error(xhr.responseText);
console.error(thrownError);
});
}), 5000);
});
</script>
I am using Flask for backend and Angular for frontend. I am implementing Server-Sent Events (SSE) for some task. Unfortunately, I am not able to receive any data from the SSE.
Banckend:
#app.route('/stream')
def stream():
def event_stream():
while True:
time.sleep(1)
yield 'data: some data\n\n'
return Response(event_stream(), mimetype='text/event-stream')
Frontend:
ngOnInit(): void {
var eventSource = new EventSource('http://127.0.0.1:5000/stream')
eventSource.onmessage = (e) => {
console.log(e.data); // Not working
this.eventData = e.data; // Not working
}
}
The issue with this code is the if I am commenting time.sleep(1) line in the backend, then I am able to see the response in the Chrome's dev tools, but not able to bind it in the HTML file. So, if I keep it like that, then I am not able to see either of them.
I am facing one more issue, when I am terminating the backend (by killing the command promt), I am able to see that the failed calls are still being continuously made from the browser to the event stream. I believe, SSEs are always sent from the server/backend, but in this case the client/browser is requesting for the event. Is my understanding wrong?
I have attached an image for reference.
Use eventSource's addEventListener method:
eventSource.addEventListener('message', (e) => {
this.eventData = e.data;
});
eventSource.addEventListener('error', (e) => { // This will properly close the stream, when it ends.
eventSource.close();
});
I am trying to make web application which takes temperature and (motor)RPM from sensors coming through my computer which connected serially to a mechanical machine and display it on web page.
I am using Python Flask with AJAX. What I've tried so far now is took jsonify data from back-end and displayed on html page. But I am not getting or seeing any real time data changing on web page without reloading the page. I need to reload the page every time to see data changing.
How can I and what are the possible ways to get this data displayed on web page.
This is my python script for flask app:
from flask import Flask, render_template, request, jsonify
import random
import time
import serial
app = Flask(__name__)
#app.route('/')
def hello_world():
return render_template("index.html")
#app.route('/ret_num', methods = ['POST', 'GET'])
def ret_num():
s = serial.Serial('COM7')
res = s.read()
time.sleep(1)
return jsonify(res)
if __name__ == '__main__':
app.run(debug = True)
And HTML code:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<script>
$(function(){
$.ajax({
url: '/ret_num',
type: 'POST',
success: function(response) {
console.log(response);
$("#num").html(response);
},
error: function(error) {
console.log(error);
}
});
});
</script>
<h1>Output</h1>
<h1 id="num"></h1>
</body>
</head>
</html>
There are two good ways of doing this:
Polling
Essentially, you'll have to call your API on a loop at a small interval, say 30 seconds.
This can be achieved by using something like (code may not work as is, but the principle remains the same):
setInterval($.ajax({
url: '/ret_num',
type: 'POST',
success: function(response) {
console.log(response);
$("#num").html(response);
},
error: function(error) {
console.log(error);
}
}), 30000);
Using WebSockets instead of plain AJAX calls. Read docs here.
(Bonus) You can reload your page at an interval. For example, to reload every 30 seconds:
setInterval( location.reload(), 30000);
I've passed the last 5 hours trying to find a solution that's been bugging me since yesterday. I am writing some BDD tests using behave and selenium to test the product addition functionality of my web app.
So to add a product the user have to click on a button which will launch a dialog box containing the form that will allow him to fill in the details of the product he wants to add. When the user clicks on submit the dialog box disappears and a JS code updates a datatables table with the new product using an Ajax request.
When I launch my test selenium finds the product addition form and fill in the details I provided, the problem is that when it clicks on submit basically nothing happens, my JS code isn't executed. Here's the behave code that submits the form:
#when(u'I click on Add new product')
def subscribe_click(context):
context.browser.find_element_by_id('add-submit').click()
and what follows is the JS function that really handles the form submission
function submitEditForm(form, upload_data)
{
data_serialized = $(form).serializeArray();
data = {
'csrf_token': data_serialized[0].value,
'name': data_serialized[1].value,
'description': data_serialized[2].value,
'price': data_serialized[3].value,
'image': upload_data.data ? upload_data.data.image : ""
};
$.ajax({
type: "PUT",
url: "/api/products/"+row_data[0],
data: data,
dataType: "json",
success: function(data) {
$("#edit-frm").fadeToggle("fast");
new_data = [
data['name'],
data['description'],
data['price'],
data['image']
]
$('#myTable').dataTable().fnUpdate(data.data, row_index, undefined, 1);
},
error: function (resp) {
$("#edit-frm").fadeToggle("fast");
alertify.alert("There was a problem with your request please try again.")
}
});
}
So what I want to is: is selenium even capable of running Ajax requests? And if that's not the case what do I need to do so that my test works??
I wanted to use facebook's like button for voting on my page. Unfortunately when 'Like' is clicked I get 3-5 requests to my function instead of only one. Is there a way to prevent this ?Sample code:
FB.Event.subscribe('edge.create', function(href, widget) {
console.log(href, widget);
});
My code:
FB.Event.subscribe('edge.create', function(href, widget) {
$.ajax({
type: "POST",
url: "/votes/register",
data: "href="+href,
dataType: 'json',
success: function(data){
$(".list-submissions").html(data["html"])
}
});
return false;
});
Or maybe I can block this from the function's side using django ? Here's my function code:
def register_vote(request):
ip = request.META['REMOTE_ADDR']
url = request.POST.get("href", "")
id = os.path.basename(url)
try:
vote = Vote.objects.filter(ip=ip, id=id)
except:
vote = None
if not vote:
vote = Vote(ip=ip, uid=id)
vote.save()
html = render_finalists(request)
ajax = simplejson.dumps({
"html": html
}, cls=LazyEncoder)
return HttpResponse(ajax, mimetype='application/javascript')
I do facing slightly same issue, have been creating like buttons on the fly using AJAX, specific to the content but 'edge.create' some how storing the event and incrementing the edge.create events and firing multiple times when I click on another FB like widget.
Have bee hitting my head so badly, no luck till yet :(
Any quick help, should be appreciated.
Finally I cracked it, just compared the response which I was getting from the response object to the one which I needed to pass and that works.
FB.Event.subscribe('edge.create', function(response) {
if ( response.toString() == shareUrl.toString() ) {} }
You might get multiple requests to you callback function if the Facebook core JS SDK has been referenced multiple times, i.e. the following script tag (or variations) are more than once:
<script src="http://connect.facebook.net/en_US/all.js"></script>