JSON passed from Python (Flask) into JavaScript is displaying on screen - javascript

I am passing a JSON from a Python back-end into my front-end JavaScript where I'm running a webGL (three.js) animation. The JSON holds numerical values that determine what happens in the animation. My problem is that while I have a basic ajax request working, the JSON is being printed to the screen (in lieu of the animation) rather than becoming a variable I can iterate through to control aspects of the animation. The two halves of the call are shown below.
I asked a related question to this one before and got some great help, but am obviously still missing a piece of the puzzle. I've been reading docs and all sorts of sources, yet need a nudge in the right direction to finally get this working. Any help is appreciated!
In the python backend:
from flask import Response, json, render_template, jsonify
from app import app
from motifs import get_motif, get_motif_list
#app.route('/')
def index():
motifs = get_motif_list(10)
# The first version of the return below successfully sends data, yet it is printed to the
# screen, rather than being stored as data in a variable.
return Response(json.dumps(motifs), mimetype='application/json')
# This version of the return does not work:
# return render_template("index.html", motifs = motifs)
In the JavaScript (note that the console.log sanity checks don't work - I have no idea why:
function foo() {
var array_data;
$.ajax({
type: "GET",
url: "/",
dataType: "json"
});
request.done(function(JSON_array) {
array_data = JSON.parse(JSON_array)["array"]
console.log(array_data); // sanity check - doesn't work
});
return array_data;
};
var array = foo();
console.log(array); // sanity check - doesn't work
UPDATE
With help from the advice below, I'm pretty close to having this off the ground. The JSON is no longer printing to the screen (an issue caused by the Flask return), and I've solved a multifunction callback issue I discovered along the way. However, I am now getting a parsererror from the complete textStatus. I think the problem now lays in the Python/Flask (see current code below). Thanks again for all who've helped!
Python/Flask (I think the problem is here - I'm a noob to Flask):
from flask import Response, json, render_template, jsonify
from app import app
from motifs import get_motif, get_motif_list
#app.route('/')
def index():
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
The JavaScript (the data is returned by the Deferred object - used to solve a callback issue):
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/",
dataType: "json",
success: deferredData.resolve(),
complete : function(xhr, textStatus) {
console.log("AJAX REquest complete -> ", xhr, " -> ", textStatus)}
});
return deferredData; // contains the passed data
};

It turns out I had a lot of problems in my code above, several of which I had to debug in related questions here and here.
Among them were:
in my original Flask index() function, it was dumping the JSON data to the screen because I was not rendering the index.html template anywhere.
I had matching routes ('/') and function names (index()) in the Flask functions
As mentioned in the comments I did an unnecessary double parsing of the JSON with dataType: json and array_data = JSON.parse(JSON_array)
the return from this asynchonous function always came up undefined because it was referenced before the call had resolved
in my later update to a Deferred object, the success property should have read: success: function(data) { deferredData.resolve(data);}
So, after all those fixes, here is the functioning code!
Flask/Python:
from flask import Response, json, render_template, jsonify
from app import app
from motifs import get_motif, get_motif_list
#app.route('/ajax')
def ajax() :
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
JavaScript: (note: this is the foo() function in my question above)
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/ajax",
dataType: "json",
success: function(data) {
deferredData.resolve(data);
},
complete: function(xhr, textStatus) {
console.log("AJAX Request complete -> ", xhr, " -> ", textStatus);
}
});
return deferredData; // contains the passed data
};
// I used the Deferred structure below because I later added Deferred objects from other asynchronous functions to the `.when`
var dataDeferred = getData();
$.when( dataDeferred ).done( function( data ) {
console.log("The data is: " + data);
});

In your javascript:
function foo() {
var array_data;
$.ajax({
type: "GET",
url: "/",
dataType: "json"
});
request.done(function(JSON_array) {
/*JSON_array is already parsed and it is an object..*/
array_data = JSON.parse(JSON_array)["array"]
/* ^ I belive you dont have to do this ^*/
console.log(array_data);
/* ^ change this to console.log(JSON_array);*/
});
return array_data;
/* ^ change this to return JSON_array;*/
};

Related

Ajax call to Python script. What am I missing?

What am I doing wrong here please. I want to run an very basic python script on the server side and the get the return value to the client side (ie javascript)
My python script is:
// Hello.py
--------------------------
import sys
def hello(str):
print('Hello ' + str)
return 1
if __name__ == '__main__':
hello(*sys.argv[1:])
and my Ajax call:
function getAjax(url, data){
return $.ajax({
type: 'POST',
url : url,
data: data,
success: function(response) {
return response;
}
});
}
getAjax("./scripts/hello.py", 'John').done(function(response){
console.log(response);
});
When I run getAjax the console.log(response) statement just prints the text (ie code) in my Python script. What is the step I am missing here please?
You need a server for link an http request from your browser on a specific port (default 80) of your network target and get the reponse of a specific script, the most simple usage for local tests like this in python is to use something like simplehttpserver: https://docs.python.org/2/library/simplehttpserver.html

How to access data passed into Flask with an AJAX call?

I am working on a project that displays hotel and airbnb data using flask and a sql database. We are trying to create a "favorite button" so the user can favorite/unfavorite listings. I've got an AJAX call to a Flask endpoint that will the make corresponding SQL queries to the "favorites" table. My problem is, I can't seem to access the data I'm passing into Flask.
Here is my AJAX call on the client-side:
function unfavoriteClicked(uid, itemid, type){
$.ajax({
type: "POST",
url: "/unfavorite",
data:{uid:uid, itemid:itemid, type:type},
contentType: 'application/json;charset=UTF-8',
success: function(data) {
console.log(data);
},
error: function(jqXHR) {
alert("error: " + jqXHR.status);
}
});
}
And here is my Flask code:
#app.route('/unfavorite', methods=["GET","POST"])
def unfavorite():
if request.method == "POST":
return request.form
return "this shouldn't happen"
Note that I've taken the SQL logic and other things out since I've figured out that I am not accessing the data correctly in Flask.
I am sure that the AJAX request goes through, because when I return something like "hello", it shows up in the console log. However, when I try to access the data dictionary I'm passing in, it returns a "500 internal server error" or some other kind of error depending on what I'm trying to access. I've tried to access a bunch of different things from looking at other stackoverflow posts (like request.form['data'], request.data, request.args, etc) but nothing seems to allow me to access the data. However, it does seem to allow me to access "request.method".
I was wondering if there is something fundamental that I am missing here that would be a reason why I cannot pass in data to Flask? Or any other suggestions for doing this "favorite" button are appreciated. Thanks!
So considering the main issue that you want to tackle is accessing the data that is been passed by your web page using Ajax. I have a solution which might work in your case.
So there are two parts in which i will explain how you can solve this problem.
1) Passing the data to your python controller/function to further process the data.
$.post("url_to_which_you_want_to_pass_data", {variable_name_to_access_in_python:any_value/variable_from_front_end},
function(response, status){
call_back_function_code
});
2) Accessing the data that has been passed from the webpage in python flask
#app.route('/unfavorite', methods=["GET","POST"])
def unfavourite:
if request.method == "POST":
any_variable_name = request.form.get("variable_name_to_access_in_python","")
print(any_variable_name) #If you want to print
return any_variable_name #If you want to see any_variable_name on web
return None
Hope it Helps! Cheers :)
I don't know if it's the best option, but its worked for me.
JavaScript:
var data = [1, 2, 3, 4]
var frontend_data = {'list':data}
$.ajax({
url: "/unfavorite",
contentType: 'application/json',
type: "POST",
data: JSON.stringify(frontend_data),
dataType: 'json',
success: function(result) {
console.log("Result:");
console.log(result);
}
});
Flask:
#app.post('/unfavorite')
def unfavorite():
data = request.get_json()
print(data['data']) #[1, 2, 3, 4]
return jsonify(data)

AJAX not changing/redirecting from login page to dashboard [flask backend]

I am using the post method for the login. My ajax function sends the data successfully to my flask backend server [I know because it returns a response to my ajax]. Supposedly, after receiving the respnse from the backend, my ajax success handler will navigate/redirect to the dashboard page but IT DOES NOT! How do I make it navigate/redirect to another page/url?It returns a 200 status code so I do not know why it does not display the dashboard page.
WHAT I HAVE TRIED:
I have tried using window.location.href, window.location.replace but to no avail, still it does not work. I have also tried changing the method to GET but its still the same. I have also set async to false because ajax would not post if I would not set it to false.
AJAX
$.ajax({
type: "POST",
url: 'http://127.0.0.1:5000/processlogin',
data: JSON.stringify(loginobject),
contentType: "application/json;charset=utf-8",
async: false,
success: function (resp) {
window.location.href = ("http://127.0.0.1:5000/dashboard");
},//success
failure: function (resp) {
alert(resp.message);
}
});
backend flask functions
This functions work 100%. Already tested it with POSTMAN. I have also queried the database using my stored procedure and it does well.
This displays the login form
#app.route('/', methods=['GET','POST'])
def login():
return render_template('login.html')
This processes the ajax's sent data. In short this is the function ajax is communicating with
#app.route('/processlogin', methods=['POST'])
def processlogin():
loginobject = request.get_json(force=True)
username = loginobject['username']
password = loginobject['password']
try:
dbpassword = callstoredproc("getpassword", (username,))[0][0]
if dbpassword == 'null':
return jsonify({'status':'error', 'message':'Username does not exist!'})
elif bcrypt.verify(password, dbpassword) == True:
return jsonify({'status':'ok'})
except Exception as e:
print(e)
And this is what I am trying to display: the dashboard html
#app.route('/dashboard', methods=['GET', 'POST'])
def dashboard():
return render_template('dashboard.html')
Remove the curved brackets and try again:
window.location.href = "http://127.0.0.1:5000/dashboard";
It works also with curved brackets so just be sure that your response arrive correctly to the success callback.
See also best answer on SO.
It should also be error instead of failure as error callback.
error: function (resp) {
alert(resp.message);
}
jsfiddle Example

Updating info on html page using Ajax in Django

I have a problem with Ajax and how can I update info on my HTML page without reloading it.
So, I have a function in my views.py file:
def index(request):
some stuff
context = {
some stuff
}
return render(request, "header.html", context)
And I just use variables from {context} in my header.html file. And the question is - how can I perform index function and send new variables to my header.html file without reloading it?
First, create a new endpoint to get the desired data in whichever format. I prefer JSON.
New endpoint:
# views.py
from django.http import JsonResponse
def new_endpoint(request):
"""Returns `JsonResponse` object"""
# you can change the request method in the following condition.
# I dont know what you're dealing with.
if request.is_ajax() and request.method == 'GET':
# main logic here setting the value of resp_data
resp_data = {
'html': 'stuff',
# more data
}
return JsonResponse(resp_data, status=200)
Then, you need to code the AJAX part calling this endpoint with the method, data, headers, etc. and finally, define the success callback method to get the desired data.
AJAX:
var data = {};
$.ajax({
url: '/your-new-endpoint-url',
type: 'GET',
data: data,
dataType: 'json',
success: function(resp) {
$('#changingElement').html(resp.html);
}
});
You can send any type of data from this new endpoint to change whatever element's html text or class name or styles, etc.

Flask Ajax return multiple statuses before execution

I've got a web front-end for a flask app that is doing some heavy calculations on the back-end before passing the calculated data via JSON to the front-end to get charted.
The issue is, the calculation takes several minutes, and ideally I want the front-end to know the % done and status of the request rather than sitting there quietly.
JS Ajax request front-end:
function runBacktest() {
$.ajax({
type: "POST",
url: '/backtest',
data: {
run_partial: 1,
use_saved_model: false,
saved_model_file: 'model.h5'
},
dataType: "json",
success: function(data) {
//Successful data
},
error: function () {
alert('There was a problem contacting the server.');
}
});
}
Python backend:
#webapp.route('/backtest', methods=['POST'])
def backtest():
print('> Running Backtest...')
"""Calculation code goes on here"""
print('Percent Completed: \r{0:.1f}%'.format(round(pct_done,1)), end='')
"""Serialise each agent instance into a dictionary and put in list to be converted to JSON object"""
agents_serialised = [agent.__dict__ for agent in bt_engine.agents]
return json.dumps(agents_serialised)
Question is, how can I pass something like the percentage done, which I'm printing on stdout, on every change of percentage, to the front end? Followed by then passing the json data once it's finished?
A more Flasky approach would be to pass a generator to the response. From what I've read, this is the preferred approach to streaming data with Flask. Here's a very abstract example. Look here for my answer to different question where I have a more fleshed out and tested script using a generator in a response.
def do_calcs():
while(more_calculations):
"""do your calculations and figure out the percentage."""
agents_serialized = [agent.__dict__ for agent in bt_engine.agents]
yield json.dumps({percent: percent, agents: agents_serialized})
And in your route:
return Response(do_calcs(), mimetype='text/json')
For updating the percentage kind of stuff we need socket connection between Front end and Back end .Flask have a great package do this which is socket.io. And there is javascript support also for the socket.io.
Blog post which help to build this
I am sure you can build with this, because i done it before.
Sample Python code:
from flask import Flask, render_template
from flask.ext.socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('my percentage event', namespace='/test')
def test_message(message):
#create pertage opertion here
emit('percentage status', {'data': message['data']}, broadcast=True)
Sample javascript code:
$(document).ready(function(){
var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
socket.on('percentage status', function(msg) {
//portion for update the percentage
});
});
These code are not exactly, But you can use as reference.

Categories

Resources