flask render_template doesn't work on AJAX post - javascript

I have a site that makes an AJAX post to a Flask route.
I know there are many similar questions (please don't mark as duplicate) that use the AJAX success method to handle the response. That would work in my simplified example, but the route in my actual code is pulling a bunch of data from a database that gets rendered to multiple tables. I'd prefer not to rewrite all the table data updates in JavaScript, so I really just need to re-render the template.
python:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def hello_world(message=None):
return render_template('test.html', message=message)
app.run()
html
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
$('#mybutton').click(function () {
$.post(window.location.href, {'test': 'test'});
});
});
</script>
</head>
<body>
{{ message }}
<button id="mybutton" name="mybutton" type="button">Click Me!</button>
</body>
</html>

I've looked for the answer to this question on many pages and none of them worked until I found the one that releases the AJAX call so that the rerender is allowed to take place:
$('form').on('submit', function(event) {
$.ajax({
type: 'POST',
url: "{{ url_for( 'myServerFunction' ) }}",
data: JSON.stringify({'myId':bunchOfIds}),
contentType: "application/json",
success:function(response){ document.write(response); }
})
The most important line is the success line that releases the document so that it can be rerendered.

When you send POST request through AJAX, the request comes from javascript and response data from flask will be stored in a Javascript object. The browser itself doesn't directly send or receive anything, so it won't re-render the page.
You need to define another endpoint in your Flask app to return json data for your POST request, and use AJAX to manipulate the DOM using the returned json data.

Ok, why don't you just send a 'yes or no' flag from your flask app. Since you want to show the success or failure message without page refresh, getting jquery to update the DOM when your flask app returns a result. Something like
return message in your flask app might do the trick accompained by
success: function(e)({ $('body').append(e);});. Can't produce more code due to word length restriction on my phone, but tweaking your code along mine gets the job done. Cheers!

Related

Re-rendering with render_template not working

Flask is not re-rendering the template page with the new variable.
Flask code (app.py):
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
#app.route("/",methods = ['GET', 'POST'])
#app.route("/<value>",methods = ['GET', 'POST'])
def index(value=1):
print(value)
return render_template('home.html',number=value)
#app.route("/next",methods = ['GET', 'POST'])
def next():
if request.method == 'POST':
last_num = list(dict(request.form).keys())[0]
last_num = int(last_num)
return redirect(url_for("index",value=last_num+1))
if __name__ == '__main__':
app.run()
HTML page (home.html):
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(function() {
$('#submit').click(function() {
$.ajax({
url: '/next',
data: String(Number(document.getElementById("number").textContent)),
type: 'POST',
success: function(response) {
console.log("Awesome");
},
error: function(error) {
console.log(error);
}
});
});
});
</script>
</head>
<body>
<div id="number">
{{number}}
</div>
<button type="button" id="submit">Next</button>
</body>
</html>
The (last) number in HTML page nicely reaches the flask code and the index function gets the incremented value also. But the HTML page do not reload with the new number variable.
Couple things.
Firstly, you can interpolate your flask variables directly into your
JavaScript. It may cause errors in your editor (not in this case), but when the page renders, it will work
properly. (ie. data: "{{ number|safe }}")
Secondly, you are not redirecting the client. You are returning a redirect from your API call, but you are not following it. That function only works if you were rendering the /next endpoint as your page. You should instead return the URL you want the client to navigate to. You can set the page URL a number of ways in JavaScript. If you just want to reload the page, put location.reload(true) in your success handler. (by putting forceGet to true, you will prevent the browser for reloading from the cache so the server will actually update the variable on the page). Note that if you do this, you will need to store the variable globally on your backend as it will not update otherwise. That might be your problem now (if you are manually reloading the page each time): your variable is only being passed via the redirect which again, you are not following and rendering.
Finally, I would say there are better ways to accomplish what you are trying to do. Maybe store the variable locally and update it in a database remotely. No need to reload the page for something this trivial.
Hope this helps. Please let me know if I have misunderstood your problem or I have made a mistake.

jQuery $.post and $.ajax POST requests don't work with app.post() method in Express

I need to send data from the front-end of my Express application, to the back-end, and then render a page using EJS which needs to display that data.
The problem is the app.post() method, and subsequently the res.render() function do not seem to execute fully or properly when I make a "manual" POST request via $.post or $.ajax
Suppose I make this POST request via JQuery
$.post("/test", {
testData: 'Some test data.'
});
Or this POST request via AJAX
$.ajax({
type: 'POST',
data: {
testData: 'Some test data here.'
}),
url: '/test',
})
And I configure my app.post() method to handle that route in Express
app.post('/test', function(req, res) {
res.render('./test.ejs', {
testMessage: req.body.testData
});
});
The variable testData will be sent through and received by the app.post() method. So say if I did this: console.log(req.body.testData), the output would be Some test data, so there's no problem there.
The problem is with the res.render() function, it simply doesn't work at all if the POST request is made through $.post or via AJAX$.ajax. The res.render() function does not execute or render the page through POST requests made through $.post or $.ajax.
Strangely, if did the same POST request via a form (which I do not want to do in my application because the POST request is not supposed to send data received from an input), with the EXACT same app.post() route handler in Express it works perfectly.
For example, using a form like the one below works and allows res.render() to display the page, whereas the $.post() and $.ajax methods do not. Why is that so?
<form id="form-test" role="form" action="/test" method="post">
<input type="text" name="testData" placeholder="Test Data Goes Here" class="form-control" required>
<button class="btn" type="submit">Submit</button>
</form>
I've found another question on StackOverflow extremely similar to mine, but with no clear workaround other than the form option (which I cannot use) : Express.js Won't Render in Post Action
Any suggestions?
The point of using Ajax is that the HTTP response is returned to JavaScript and does not replace the whole page.
If you want to load a new page, then don't use Ajax. Use a form.
If you want to handle the response in JavaScript then you need to add a handler for it.
$.post("/test", {
testData: 'Some test data.'
}).done(function( data, textStatus, jqXHR ) {
// Do something smarter than
alert(data);
});
As others have pointed out, jQuery .post, .ajax, etc doesn't expect a redirect, it expects JSON, so that doesn't work. However, you can get the effect you're looking for with some easy JavaScript. This is how I did it when I had a similar problem:
First, I created a URL string, appending the data I wanted to pass to the server as query parameters
var urlString = 'http://hostaddress/myRoute?data1='+myData1+'data2='myData2;
Second, I did a window.location.replace like so:
window.location.replace(urlString);
Third, I made a GET route in Express to handle the incoming request:
app.get('/myRoute', function(req,res){
var myData1 = req.query.data1;
var myData2 = req.query.data2;
res.render('myView',{data1:myData1,data2:myData2});
Hope that helps.
I faced the same problem and solved it without using $.post or $.ajax. First of all, I took button out from form element:
<form id="form-test" role="form" action="/test" method="post">
<input type="text" name="testData" placeholder="Test Data Goes Here">class="form-control" required>
</form>
<button class="btn" type="submit">Submit</button>
And I binded posting form condition to click event of button. I could also post my desired value. For example:
$(".btn").click(function(){
if($(".form-control").val() ){
$(".form-control").val("Desired Value");
$("#form-test").submit();
}else
alert("TestData is empty");
});

Javascript to Django views.py?

This may sound simple, but how do I send the data from a Javascript array in my index.html template to my views.py?
When the user clicks a "Recommend" button, my code calls a function that accesses my database and prints a name on the template.
def index(request):
if(request.GET.get('Recommend')):
sql_handler.recFunc()
context['name'] = sql_handler.name
return render(request, 'polls/index.html', context)
I have an array of checkbox values in Javascript that are calculated after the user presses "Recommend". I want to send it to my index view and use it as the parameter for another function.
So:
def index(request):
if(request.GET.get('Recommend')):
sql_handler.recommend()
context['name'] = sql_handler.name
//something??
tags = check_array_javascript
context['tags'] = tags
return render(request, 'polls/index.html', context)
How can I do this? I've been searching similar questions, but I'm new to Django and web development in general, so I either did not understand the answers or they didn't help me.
Alright, so for sending data from the client (JavaScript) to the backend (your Django app) you need to employ something called Ajax, it stands for Asynchronous JavaScript and XML.
Basically what it does is allowing you to communicate with your backend services without the need of having to reload the page, which, you would have to do using a normal POST or PUT form submission.
The easiest implementation is using jQuery. jQuery is first and foremost a DOM manipulation library but since its inception has grown to encompass much more than that.
A jQuery ajax call looks like this.
$(document).ready(function() {
$.ajax({
method: 'POST',
url: '/path/to/your/view/',
data: {'yourJavaScriptArrayKey': yourJavaScriptArray},
success: function (data) {
//this gets called when server returns an OK response
alert("it worked!");
},
error: function (data) {
alert("it didnt work");
}
});
});
This can then be checked for in your views.py
def index(request):
if request.is_ajax():
#do something
request_data = request.POST
return HttpResponse("OK")

Calling a function from a template using javascript

I'm very new to Django and there's something I'm trying to do that I don't seem to understand how. Right now I have elements of the page show/hide using javascript onclick. What I'm showing includes a dropdown box. What I would like to do is to call a python client side function I wrote, passing the choice and thus making changes to the database. The function is written and I have the frontend working but I don't understand how to take the submit button and get the javascript to not only show/hide elements but end up calling this function.
I don't want the page to refresh which my research so far leads me to believe I need to use AJAX and some sort of POST. Not really sure about that. I've got no experience with this kind of thing. I was wondering if I was on the right track or somewhere that might help me get there/a guide of some kind.
You are correct, you will need to use AJAX. Here is quick example:
template.html
<button type="button" id>Click Me!</button>
{% block inline_js %}
<script type="text/javascript">
$(document).ready(function () {
$(document).on("click",'#button',
function() {
$.ajax({
type: "POST",
data: { action: "delete"},
success: function(data){}
</script>
You can put your AJAX functions directly in your view. If you put nothing in your 'url' argument of your AJAX call, it will call itself (your view that called it).
views.py
def post(self,request, *args, **kwargs):
#Add a AJAX request check. If it is AJAX, redirect to AJAX function
if self.request.is_ajax():
return self.ajax(request)
#===========================================================================
# AJAX
#===========================================================================
def ajax(self, request):
response_dict= {
'success': True,
}
#Your SQL DROP code here...
return HttpResponse(simplejson.dumps(response_dict), mimetype='application/json')
You have to make POST request with JavaScript, and receive it on the server. The basic idea: you send data (JSON, maybe) from the client using XMLHttpRequest or $.ajax (if your project uses jQuery). It is in theory, I am not familiar with Django as well. But according to the docs Django can not handle AJAX by default, so it seems to be what you need: http://www.dajaxproject.com/dajaxice/

python code from javascript using ajax

I have seen this topic: ajax request to python script where they were trying to do exactly what I need but there is one information missing.
$.post('myPythonFile.py',{data},
function(result){
//TODO
}
);
Now my problem is: how do I call a certain function which is inside myPythonFile.py? Is there a way to specify the name of the function and to give it my input data?
Thank you very much for your time.
Ajax calls making HTTP requests,so you need to have a HTTP server which handles your requests as it is seen in the other question. (There is CGI which provide HTTP request handling). In Python you can use DJango, Bottle, CGI etc to have HTTP request handling. to call python function from javascript.
Edited :
in your url.py you should define your api url;
(r'^myAPI', 'myAPI'),
and on this url you should have a web API in views.py. It can be like ;
def myAPI(request):
callYourFunction();
and you can call it from Javascript now. You can use JQuery for AJAX request;
$.ajax({
type:"GET",
url:"/myAPI",
contentType:"application/json; charset=utf-8",
success:function (data) {
},
failure:function (errMsg) {
}
});
The HTTP method type does not matter, if you only wanna run a Python script. If you wanna send data from javascript to Python you can send the data as JSON to Python as POST method.

Categories