I'm new to Flask and AJAX and my current challenge is that when I make an AJAX request to the server my result is undefined. I am using deferred objects to keep track of several asynchronous requests, and all are working except for the AJAX function shown below. The other two are non-AJAX. Likely problem areas in the code below are marked with >>>>
For context, I am writing the backend to a one-page animation in the browser. The template remains the same regardless of any requests (clicks) from the viewer or any data requests the animation makes on its own programmatically (periodic adding and subtracting of visual material).
Flask/Python:
from flask import Response, json, render_template
from app import app
from motifs import get_motif_list
# >>>> can/should I use two functions aimed at the same route? Not sure how to both render the template and pass data
#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")
JavaScript:
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/",
dataType: "json", // >>>> when I comment this out I get an error, when I leave it in I get a parsererror
success: deferredData.resolve(),
complete: function(xhr, textStatus) {
console.log("AJAX REquest complete -> ", xhr, " -> ", textStatus);
}
});
return deferredData; // contains the passed data >>>> currently undefined!!!
};
// DEFERRED OBJECTS
// used to perform a callback after multiple asynchronous functions
var deferredData = getData();
var deferredWindow = windowLoaded();
var deferredImages = loadImages();
// SINGLE CALLBACK AFTER MULTIPLE ASYNCHRONOUS FUNCTIONS
$.when( deferredWindow, deferredData, deferredImages ).done( function( window, data, images ) {
console.log("The window has loaded - " + window); // successful!
console.log("The data are: " + data); // >>>> undefined!
console.log("The images are: " + images); // successful!
});
UPDATE:
Thanks to #Jason P the success function in the getData AJAX call is now success: function(data) { deferredData.resolve(data); } and the result is no longer undefined! Alas, it's not my data, either. I think I may have a bug (or a conceptual misunderstanding) in my Flask code because the request returns the complete text of my html template instead of my JSON data. Thoughts?
UPDATE 2
Also #Jason P's suggestion I changed the route url in Flask and the AJAX request to an alternate route: /ajax to avoid a potential(?!) clash with the template rendering. However, the request still returns the full text of my html template. Perhaps I also need to differentiate the python/flask function names? ...will try that next. Updated code below.
Python/Flask:
#app.route('/ajax')
def index():
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
JavaScript AJAX url property changed to:
url: '/ajax'
UPDATE 3
I differentiated the python/flask function names so that the /ajax route function is now called ajax(), and the root route '/' function is still called index(). The JSON object now renders to the screen (instead of being passed in as a variable) and nothing from the javascript renders (presumably now missing the template rendering?)
RESOLVED
Following on comments by #Jason P the call is finally resolved and functioning. Wheew! Here is the final code:
Flask/Python
from flask import Response, json, render_template
from app import app
from motifs import 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:
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/ajax",
// dataType: "json",
success: function(data) {
deferredData.resolve(data);
},
error: function (data) {
debugger;
alert("Error");
},
complete: function(xhr, textStatus) {
console.log("AJAX Request complete -> ", xhr, " -> ", textStatus);
}
});
return deferredData; // contains the passed data
};
// all else in the script remains the same as above...
Thanks!
This line:
success: deferredData.resolve()
Immediately executes resolve().
Try this instead:
success: function(data) { deferredData.resolve(data); }
Related
I am making a project with raspberry Pi, is a control and monitoring data through internet.
Finally I can make the communication with flask-html-JavaScript
In summary I want to update my chart js graph when the flask function response with jsonify data
I am using Ajax method with getjson but I am executing with setinterval and I don’t want to use setinterval, I want that the getjson function execute when flask function response with jsonify data
Exist any method that can make it?
this is my code in flask:
#app.route('/start', methods=['GET', 'POST'])
def start():
n = request.form['number']
print(int(n))
for i in range(int(n)):
GPIO.output(19, GPIO.LOW)
while gt.read_sensor() == 0:
pass
now0 = datetime.now()
for j in range(1):
value = adc.read( channel = 0 )
volt = (value/1023)*3.3
presure = ((volt/3.3)-0.1)*3/2
p1.append(presure)
global pon
pon = presure
time.sleep(0.25)
pon = -100
Here I capture the value sensor and I call update with global variable the function presson:
#app.route('/pon')
def presson():
return jsonify(result = presson)
and this is my javascript code:
var pon = 0;
var test = 0;
function sendData() {
$.ajax({
type: "POST",
url: "{{ url_for('start') }}",
data: { number : $('#number').val() }
});
setInterval(update_values,100);
}
function update_values() {
$.getJSON('/pon',
function(data) {
$('#result').text(data.result);
pon = data.result;
console.log(data)
});
currently that work good, but sometimes the value is not update, then I want that the function getJSON() run only when recieve a correct value (without setInterval method), what recommend me?
I am new to python and JS. I am trying to call a python method from a js code. The python code is supposed to do some calculation and returns me the results which is array of arrays (e.g., [[1,3],[3, 5]]). I have looked at few answers such as this. However, I was not able to solve my problem. Below is what I have so far:
JS code : This sends string "start" to my python code.
var a = $.post("/mlModel", {
Ml_list: JSON.stringify("start"),
contentType: "application/json",
dataType: "json"
});
console.log(JSON.parse(a));
Python Code: Python code gets the string "start", does some process, and return the results in the form of array of arrays [[2,4],[2,6]]
enter code here
#app.route('/mlModel', methods = ['POST'])
def get_post_MlModel():
jsdata = request.form['Ml_list']
jsdata = json.loads(jsdata)
jsdata = ast.literal_eval(json.dumps(jsdata))
// I send "start" to calculate method and it returns data = [[2,3],[1,3]]
data = calculate(jsdata)
return json.dumps(data)
When I run this code, this returns me "Unexpected token o in JSON at position 1"
Any idea?
jQuery.post is an asynchronous operation so a isn't ready yet when you try to use the JSON in the response. try using a callback which is called when the request is finished
$.post("/mlModel", {
Ml_list: JSON.stringify("start"),
contentType: "application/json",
dataType: "json"
}).done(function(data) {
console.log("success " + JSON.parse(data));
}).fail(function(jqXHR, textStatus, errorThrown) {
console.error( "failure " + errorThrown );
})
Here's the typical python and javascript code used while sending and receiving objects over the server. The example below sends a string ("start") from the client and returns a list of sequential index pairs as lists.
On the python side:
#app.route('/testQuery', methods=['POST'])
def testQuery():
queryString = request.form['queryString']
outputList = []
for i in range(0,len(queryString)):
char = queryString[i]
outputList.append([i,(i+1)])
return jsonify({
"outputList" : outputList
})
On the javascript side:
$.post("/testQuery", {"queryString": "start"})
.done(function (response) {
console.log(response)
});
Hope that helps.
Working in a C# ASP.NET project with JavaScript/Jquery/jqGrid.
New task is to have a page to i) accept an Excel input file, ii) use the column ID to look up additional information, and iii) generate a new Excel file using some columns from input file and all columns returned from database.
I have completed that, but just want to do a bit more error handling. In the stored procedure, if everything works fine, it returns a data table (or in Oracle term, a CURSOR). If there is an error, I have added a catch block and return an error message.
I modify the AJAX call. Beside adding dataType as 'text', I expect the return as XML.
$.ajax({
// POST
// URL: url to call that stored procedure
dataType: text,
success: function (response) {
// now the response is XML (don't know why...
// specify dataType as 'text', but get XML...)
// If response contains 'string' tag, report error.
},
failure: ...
})
Here is what I used to do. I don't specify the dataType but somehow that works.
$.ajax({
// POST
// ... rest is same but without the dataType
success: function (response) {
Download( response )
// The file is already and placed in Download directory.
// Call 'Download()' will actually make the download happen
// But here response is just a path to the Download directory +
// download file name.
And Download() is:
function Download(url) {
document.getElementById('my_iframe').src = <%=ResolveUrl("~/")%> +url;
return false
};
How can I have the success function handle both type of response?
(Just for your information: The front-end page is ASP.NET. Button click will call a JavaScript function. The function calls a web service function via $.ajax(). As there are many rows, the web service function calls a function in a database class many times - each time pass in just one ID. The function will in return call stored procedure.)
Edit: Thanks for solution from Mustapha Larhrouch. Here are some points that I have to adjust:
Add dataType.
If response is XML, check if error.
If not XML, just download.
And here is my code:
$.ajax({
// POST
// URL
dataType: "text",
success: function (response) {
if (isXML(response)) {
var xmlDoc = $.parseXML(response);
$xml = $(xmlDoc);
var errMsg = $xml.find("string").text();
if (errMsg != "" ) {
// pop up a dialog box showing errMsg
}
}
else {
Download(response);
}
you can check if the response is an xml if it's parse it, if not the response is a string. and you can use this function to check if the response is an xml :
function isXML(xml){
try {
xmlDoc = $.parseXML(xml); //is valid XML
return true;
} catch (err) {
// was not XML
return false;
}
}
$.ajax({
// POST
// ... rest is same but without the dataType
success: function (response) {
if(isXML(response){
Download( response )
}
else{
//report as error
}
I have an ajax call that fetches some JSON by hitting my controller:
class #Team
constructor: () ->
#players = null
#getTeamInfo()
getTeamInfo:(teamId) ->
request = $.ajax
dataType: 'json',
type: 'GET'
url: "http://localhost:4000/teams/#{teamId}",
async: false
success : (data) =>
_.each(data.players, (value) ->
name = _.pluck(value, 'name')
#players.push(new Player(name)))
The problem is that I need the players from the very start, and, seeing how JS runs asynchronously, the variables are null. Is there a way I can actually initialize variables with an ajax call?
UPDATE:
After getting a new perspective on the issue from #mu_is_too_short and understanding the real importance of callbacks when doing ajax calls from #Rich Peck, I was able to get my game initializing by ensuring that all the code that depended on the data returned from the Ajax call was included in the Ajax success callback. I think I may have to include all the data that I will need to build the game, not just the team and player data. But that's later. Thanks, guys.
class #Game
constructor: (homeId, awayId) ->
#homeTeam = new Team()
#awayTeam = new Team()
#display = new GameDisplay()
#pitcher = new Pitching()
#contact = new Contact()
#baseRunners = new BaseRunners()
#gameEngine = new GameEngine(#homeTeam, #awayTeam, #display, #pitcher, #contact, #baseRunners)
#initializeHomeBattingOrder(1, 3)
pitch: ->
#gameEngine.makePitch()
initializeHomeBattingOrder: (homeId, awayId) ->
$.ajax
dataType: 'json',
type: 'GET',
url: "http://localhost:4000/teams/#{homeId}",
success : (data) =>
#populateHomePlayers(data)
#initializeAwayBattingOrder(awayId)
initializeAwayBattingOrder: (awayId) ->
$.ajax
dataType: 'json',
type: 'GET',
url: "http://localhost:4000/teams/#{awayId}",
success : (data) =>
#populateAwayPlayers(data)
#display.battingOrder(#awayTeam.players, #homeTeam.players)
#display.teamsPlaying(#awayTeam.name, #homeTeam.name)
populateHomePlayers: (data) ->
#homeTeam.players = _.map(_.pluck(data.players, "name"), (name) -> new Player(name))
#homeTeam.name = data.name
populateAwayPlayers: (data) ->
#awayTeam.players = _.map(_.pluck(data.players, "name"), (name) -> new Player(name))
#awayTeam.name = data.name
I was going to write this as a comment, but I figured it would be easier to read in an answer. I'll delete if inappropriate, as I don't think I can provide a direct solution, rather some more info about working with Ajax
Asychronous Javascript And XML
Ajax is designed to run asynchronously by default, and actually freezes your browser if it's forced to run synchronously (by using async: false)
We found this out the hard way, as we were trying to find a way to use it to call some variables & discovered you cannot "just use ajax" -- you have to design around it
Using Callbacks With Ajax
We wanted to render a form "on the fly", which required data to be called by Ajax. The problem was that instead of just fitting Ajax into the exiting code, we had to refactor it so that the Ajax part of the code ran independently to the "static" parts. We fixed it by using ajax callbacks
Here's our code:
function create_modal(o){
//o.ajax = the link to use. If present, it means we use Ajax :)
if(o.ajax){
//Loading
fetch_modal(o.ajax, function(data){
var modal = document.createElement("div");
modal.setAttribute("id", o.modal_id.substring(1));
modal.className = 'modal ajax';
modal.innerHTML = data;
$("body").append(modal);
overlay();
show_modal(o);
}, function(data){
//error
});
}else{
overlay();
show_modal(o);
}
}
function fetch_modal(link, success, error) {
$.ajax({
url: link,
success: function(data) { success(data); },
error: function(data) { error(data); }
});
}
You can see a demo of this working at http://emailsystem.herokuapp.com (register & then click the "New List" / "New Broadcast" / "New Subscriber" button) -- that form is rendered through ajax
CoffeeScript formatting aside, I think the best thing you can do is to employ a callback function for Ajax, and make Ajax the central component in your function, like this:
class #Team
constructor: () ->
#players = null
#getTeamInfo(teamId, ->
_.each(data.players, (value) ->
name = _.pluck(value, 'name')
#players.push(new Player(name)))
, ->
//error
getTeamInfo:(teamId, success, error) ->
request = $.ajax
dataType: 'json'
type: 'GET'
url: "teams/#{teamId}"
success : (data) => success(data)
error : (data) => error(data)
I have scoured this site and elsewhere trying to solve the problem I am having with jsonp. To start things off, here's the code that I have:
url = "http://mydomain.com/return_json";
$.ajax({
url: url, // + '?callback=?' --I realized this is not necessary with dataType: 'jsonp'
dataType: 'jsonp',
crossDomain: true,
error: function(xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
},
success: function(dataWeGotViaJsonp){
var text = '';
var len = dataWeGotViaJsonp.length;
for(var i=0;i<len;i++){
item = dataWeGotViaJsonp[i];
text += '<p>' + item + '</p>';
}
$('#action_target').html(text);
}
});
On the sending side, the /return_json url is a Django site that is sending json data the following way:
def return_json(request):
data = [{'testing': 'testing'}, {'one': 1, 'two': 2, 'three': 3}]
return HttpResponse( json.dumps(data), content_type="application/javascript" )
As you can see in the JavaScript, I'm indescriminately dumping everything into the console on error. Here is the output of that:
Object { readyState=4, status=200, statusText="success"}
parsererror
Error: jQuery110207276483389928793_1377030169256 was not called
The 'net' area of firebug shows that the url was:
http://mydomain.com/return_json? callback=jQuery110209170565296948737_1377029879665&_=1377029879666
It also shows that valid JSON is in the response. It even has a JSON section with a pretty-fied output. So, obviously my problem is that the jQuery auto-generated callback function is there, but not getting called. I get the same result using the $.ajax and $.getJSON methods set up for jsonp. The only thing I can think of at this point is that I'm supposed to wrap the json data in a function somehow on the sender's side, but I was under the impression that the receiver takes care of that. If anyone can see what I'm doing wrong, it would be much appreciated.
=================================UPDATE WITH FULL ANSWER========================
Hamish has the correct answer below, although it just needs two minor tweaks. Here is how you can send data in JSONP format using Django:
def return_json(request):
# ^--------I didn't need a parameter in this situation
json_data = ["one", "two", "three"]
return render_to_response("uitest/jsonp_template.html", Context({
'callback': request.GET.get('callback'),
'json': mark_safe(json.dumps( json_data )),
# ^------------------------------This keeps your JSON from getting mangled in
# URL
}), mimetype="application/javascript")
#^---------------------This closing parentheses was missing in Hamish's answer at the time
# of this writing.
A JSONP response is actually a script response - something like:
callbackFunctionName([{'testing': 'testing'}, {'one': 1, 'two': 2, 'three': 3}]);
Create a template that returns a application/javascript response with a function call to function request.GET.get('callback') with the body of the JSON as the only argument.
Something like:
def return_jsonp(request, json_data)
return render_to_response("jsonp_template.html", Context({
'callback': request.GET.get('callback'),
'json': json.dumps(json_data),
}, mimetype="application/javascript")
Where jsonp_template.html is just:
{{ callback }}({{ json }});