index.html
<div >
<input type="text" id="input" placeholder="Enter expression" value="1 2"/>
<input type="submit" id="btn" value="Execute"/>
</div>
<input type="text" id="output" readonly="readonly">
<script src="{{url_for('static', filename='js/jquery-3.2.1.min.js')}}"></script>
<script type="text/javascript">
document.querySelector('#btn').addEventListener('click', (e) => {
let equation = document.querySelector('#input').value;
$.ajax({
url: "/",
type: "POST",
data: equation,
success: function(){
console.log("successfull POST");
let result = {{evaluate}}
document.querySelector('#output').value = result;
}
});
});
</script>
main.py
from flask import Flask
from flask import url_for, jsonify, render_template, request, json
from math import *
app=Flask(__name__)
@app.route('/', methods=["GET","POST"])
def index() :
evaluate = ""
if request.method == 'POST':
toEvalFromJS = request.get_json()
evaluate = eval(str(toEvalFromJS))
return render_template('index.html', evaluate=evaluate)
return render_template('index.html')
if __name__ == "__main__":
app.run(port=10, debug=True)
error
(index):26 successfull POST
(index):28 Uncaught ReferenceError: Cannot access 'result' before initialization
at Object.success ((index):28:53)
at i (jquery-3.2.1.min.js:2:28017)
at Object.fireWith [as resolveWith] (jquery-3.2.1.min.js:2:28783)
at A (jquery-3.2.1.min.js:4:14035)
at XMLHttpRequest.<anonymous> (jquery-3.2.1.min.js:4:16323)
I know what the error means but I could only get such far.
I have already read the following questions:
- jquery - return value using ajax result on success
- How to return the response from an asynchronous call
but they did not help me solve my problem.
What I want to do: User input an expression string, then click on the submit button and get the evaluated string back.
How could I get the evaluated string?
I am new to flask, I do it just for practice
CodePudding user response:
Main problem is that you use {{evaluate}}
in wrong way. You expect that JavaScript will get data from server and it will replace {{evaluate}}
with new value. But it is not true.
Flask replaces {{evaluate}}
with empty string and it sends HTML with empty string - and browser when you load page index.html
and
browser has HTML with empty string (it doesn't know that there was {{evaluate}}
).
When $.ajax
gets it agains then Flask replaces {{evaluate}}
in template index.html
and it sends new HTML with new value in place of {{evaluate}}
but it can't replace empty string which you already have in original HTML in browser - it doesn't work this way.
JavaScript
get new HTML in data
in sucess: function(data){...}
and you have to write code which uses this data
. But it could be simpler if you would send ajax to separated URL which send back only result (without other HTML). And then it can display data
sucess: function(data){
document.querySelector('#output').value = data;
}
Later there is another problem(s).
Ajax sends it with standard header for POST form
and Flask
see it and it convert data to request.form
and it has empty request.get_json
(because all is in request.form
).
But some chars has special meaning in form
and url
(ie.
is used instead of space) and it automatically unescapes data and it puts space
instead of
.
To get
you have to get raw data
using request.get_data()
Or you would have to send ajax
with header application/json
to use get_json()
.
$.ajax({
...
contentType: "application/json; charset=utf-8",
...
})
Minimal working code
I use render_template_string
instead of render_template
to put all in one file - and now everyone can simply copy and run it.
I also use https://cdnjs.cloudflare.com
to load jquery
so it doesn't need local file with jquery
.
from flask import Flask, url_for, jsonify, render_template_string, request, json
from math import * # `import *` is not preferred
app = Flask(__name__)
@app.route('/')
def index():
return render_template_string("""
<div >
<input type="text" id="input" placeholder="Enter expression" value="1 2"/>
<input type="submit" id="btn" value="Execute"/>
</div>
<input type="text" id="output" readonly="readonly">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP u1T9qYdvdihz0PPSiiqn/ /3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
document.querySelector('#btn').addEventListener('click', (e) => {
let equation = document.querySelector('#input').value;
$.ajax({
url: "/data",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(equation),
success: function(data){
console.log("successfull POST");
console.log(data);
document.querySelector('#output').value = data;
}
});
});
</script>
""")
@app.route('/data', methods=['POST'])
def data():
print('json:', request.get_json()) # `None` if there is no `contentType: "application/json; charset=utf-8"` in `$.ajax`
print('data:', request.get_data())
print('form:', request.form)
equation = json.loads(request.get_data().decode())
print('equation:', equation)
if equation:
result = eval(equation)
else:
result = "wrong data"
return jsonify(result)
if __name__ == "__main__":
#app.debug = True
app.run(port=5010)