I am trying to create a web application that allows the user to send specific data to the webserver and retrieve it to process it further into functions that visualizes information to the user.
However, when sending code from the webserver back to the client, some data values within the data become 'undefined'.
#app.route('/_create_vis_json', methods=['GET'])
def process_vis_input():
""" This function gets the inputs of the user of the MGcV viewer. It converts it into a json with all the information
needed for the visualisation of the genes.
:return: JSON containing info of genome
"""
gi_codes = request.args
search = GeneConverter(gi_codes)
processed_dictionary = (search.create_output_json())
return {'result': processed_dictionary}
Using the Pycharm debugger, I have concluded that all data is present when the data gets send to the front-end.
$(function () {
/** when a input button with name vis_button is clicked, a ajax request is send to the server containing
* information about the settings used in the viewer. A Json object containing information about the given
* genes is returned to be processed into a visualisation.
*/
$('input[name="vis_button"]').bind('click', function () {
$.ajax({
dataType: "json",
type: 'GET',
url: $SCRIPT_ROOT + '/_create_vis_json',
data: {
gi_codes: $('textarea[name="gi_codes"]').val(),
input_type: $('select[name="input_type"]').val(),
context_range: $('select[name="context_range"]').val(),
map_size: $('select[name="map_size"]').val(),
gene_orient: $('select[name="gene_orientation"]').val(),
gene_label: $('select[name="gene_label"]').val(),
gene_coloring: $('select[name="gene_coloring"]').val()
},
success: function (data) {
console.log('==========');
console.log(data);
console.log('-----');
$("#result").html(buildSVG(data.result))
}
});
});
});
Taking a look at the console log, at the inconsistent values, 1 or more of the values will be undefined. When I repeat the process, the same values go missing.
I am using Python 3.7.4 with Flask 1.1.1 and using jquery version 3.4.1
Edit 1: As indicated by Ajax1234, I have already tried to use Flask.jsonify and got the same results. I will also include a picture of the missing data.
Screenshot of console log of the browser
You can use flask.jsonify instead of returning a dictionary as the response for your route. flask.jsonify automatically sets the appropriate Content-Type headers for a JSON response:
return flask.jsonify({'result': processed_dictionary})
Additionally, if processed_dictionary is not a basic type (int, float, str), you need to convert it to a JSON string:
flask.jsonify({'result': json.dumps(processed_dictionary)})
Then, in your Javascript:
success: function (data) {
$("#result").html(buildSVG(JSON.parse(data.result)))
}
Related
What I need
I'm trying to find a way to send a multi layered dictionary via AJAX to my server, including a JavaScript seralised form with the use of serialize().
The issue
When I use data: frm.serialize();. It's a single layered json and it is easily parsed when returned to server with result:
<QueryDict: {'csrfmiddlewaretoken': ['6aTZ7xey90sczae15069ZlbIiE7gVWW69RyeJBptUxadbgnBo8t8R0Nskg8S8Jzb', '6aTZ7xey90sczae15069ZlbIiE7gVWW69RyeJBptUxadbgnBo8t8R0Nskg8S8Jzb'], 'days': ['Mon', 'Wed'], 'no_weeks': ['1']}>
Then when using a nested dictionary with
data: {'form':frm.serialize(),'additional_data':12,'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()}```
I get:
<QueryDict: {'form': ['csrfmiddlewaretoken=IF2D4vTBjaQSsrE4oY3Lb36jekPB5nZbLmHSGz4w4HyT4xNEH6qK3II3gWQdiaCg&days=Mon&days=Thu&no_weeks=2&csrfmiddlewaretoken=IF2D4vTBjaQSsrE4oY3Lb36jekPB5nZbLmHSGz4w4HyT4xNEH6qK3II3gWQdiaCg'], 'additional_data': ['12'], 'csrfmiddlewaretoken': ['IF2D4vTBjaQSsrE4oY3Lb36jekPB5nZbLmHSGz4w4HyT4xNEH6qK3II3gWQdiaCg']}>
What i've tried
I have attempted with use of this answer to use urllib to parse the form section of the data into a separate variable. Like so:
x = parse_qs(urllib.parse.urlparse(request.POST['form']).query)
This returns an empty dicitonary.
Code
HTML
<form method="post" id="replicate_form">
[..more code]
</form>
Javscript
function send_replication_data() {
var frm = $('#replicate_form')
var form_server_response = submit_formdata(frm)
}
// parent function to handle replcation form saving
$('#create_replicate_booking_button').on('click', function() {
send_replication_data()
});
// submit booking data ajax
function submit_formdata(frm) {
var tmp = $.ajax({
type: frm.attr('method'),
async:false,
url: window.location.href,
data: {'form':frm.serialize(),
'additional_data':12,
'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()}
});
return tmp.responseJSON;
}
Possibly I could somehow make use of whatever Django is doing in it's middleware to a parse the form data in the first scenario?
The .serialize() method creates a text string in standard URL-encoded notation.
You could use urllib.parse.parse_qs to parse a query string(form data sent to server by GET) or request.POST['form'] since it uses the same encoding.
Query strings are element of urls, while request.POST['form'] has no attribute called query
from urllib import parse
x = parse.parse_qs(request.POST['form']).query)
I have a python script that takes in some data and manipulates it. However i need it to run on the client side inside the javascript to process some data and refresh the view.
The python file that manipulates data works well as I have tested it inside the IDLE shell
DataManipulation.py
class ModifyData(object):
#Bunch of functions to manipulate data
below is the function used to render the view with url '.../test' which also works perfectly.
views.py
def test(request):
template = 'app/test.html'
file = 'documents/Sample.csv' #File to be loaded
args = {'test': file }
return render(request, template, args)
After loading this page, i use a javascript library that displays the data on the page in a table, the user can then manipulate the data like multiply a column by 3, but where I am stuck is how to take my DataManipulation.py file to modify the data and updates the page with the updated column on a button click
Since executing python client side is not an option, you have two options.
re-write ModifyData in Javascript and use it client side.
When a user does something like multiply a column by 3:
Use client side JS to make an ajax request to the server
Have your server call ModifyData, and then return the data to the client
have client update view with new data
I would recommend porting your python code to JS, but if that isn't possible #2 will always work. How you implement will just depend on how you manage data in the client.
I think you should pass the data into template, and then use javascript to manipulate the data, after that you can use ajax to update your page without refresh, example:
<!--html-->
<button onclick="deleteUser({{ request.user.pk }})">Submit</button>
<!---->
function deleteUser(userid) {
var post_data = {
'userid': userid,
}
$.ajax({
type: "POST",
url: "/deleteuser",// the view function to post
data: post_data,
contentType: 'application/json;charset=UTF-8',
success: function(result) {
// do something after post
...
}
});
}
the view function:
# url(r'^/deleteuser$', views.delete_user)
def delete_user(request):
if request.method == 'POST':
# do something
userid = request.POST.get('userid')
user = User.objects.get(pk=userid)
# dict contain response data
response_data = {...}
# return response
return HttpResponse(json.dumps(response_data),content_type='application/json')
I am using the Google maps Javascript API and when the user changes the directions/route on the map (draggable is set to true) I want to send the new route/directionsResult to my webservice backend. The issue I am facing is when I serialize DirectionsResults using JSON.stringify I don't seem to be getting the full list of objects correctly converted to strings.
directionsDisplay.addListener('directions_changed', function () {
sendToBackendService(directionsDisplay.getDirections());
});
function sendToBackendService(result) {
var jsonToSend = JSON.stringify(result);
$.ajax({
type: 'POST',
url: './api/DirectionsUserModified',
data: jsonToSend,
error: processCallbackError,
success: function (apiJson) {
alert("post of new directions success");
}
});
}
The issue will always be related to the local environment of execution of your JavaScript code. So , the version of web browser you are using.
Maybe the object can't be serialized properly because the size limit is reached. The navigator uses the local storage as buffer during json serialization process. If the limit is reached, the String is simply truncated or an error is thrown.
You could have a look to this other post, maybe it'll help
I am having some odd problems with data coming back from a jquery Ajax call that I cannot figure out.
I have a c# asp.net web page that binds a valid JSON data blob to the UI with client side JavaScript on page load. This part works just fine. I set up a jquery Ajax post back that returns the same data and calls the same JavaScript data binding method, and this throws an error when I attempt to bind the data. It looks like the JSON written to the page on load is properly treated as a JSON object, but the data returned by the ajax call isn't.
Here is the ajax call:
jQuery.ajax({
type: 'POST',
data: "{'move_list': '1-2,3-2'}",
dataType: 'json',
contentType: 'application/json; charset=UTF-8',
url: 'Puzzle.aspx/ProcessMove',
complete: OnComplete,
success: function(data){BindData(data);},
error: OnError
});
Here is a sample of the JSON data that is being processed:
{"game": [{"x":0,"y":0,"color":"Blue"},{"x":1,"y":0,"color":"Green"}]}
Here is the code that loads the data when the page is first loaded:
<script type="text/javascript">
// method returns JSON object above.
// client side code appears like this:
// BindData({"game": [{"x":0,"y":0,"color":"Blue"},{"x":1,"y":0,"color":"Green"}]});
BindData(<%=Game.SerializeToJson()%>);
</script>
and finally, the JavaScript binding function:
function BindData(data)
{
try
{
document.getElementById("square1").className = data.game[0].color;
// much more of the same....
}
catch(exception)
{
alert(exception.message);
// error thrown here is 'data.game is undefined'.
// the data object is being treated like a string and not a JSON object.
// so the indexing into the object fails.
}
}
I have double checked the JSON data with several online JSON parsers, and the data is formatted correctly. The server side code generates the same output in either case.
I tried to change the jquery Ajax call to...
success: function(data){BindData(JSON.parse(data));},
...to see if it was just treating the returned data as a string as opposed to a JSON object, but that just generates this message:
SyntaxError: JSON.parse: unexpected character
BindData(JSON.parse(data));
Completely stumped by this one. I have been reading everything I can find and trying all sorts of things, but nothing seems to work.
I am creating a basic piece of functionality to allow users to send their location to a server which then queries a database and returns locations near to them. I am using the below jQuery .ajax wrapper to POST data to the server. This takes the form of a latlon point which is then used as the basis for a geosearch in MongoDB using nodejs and express on the backend. The results of the search are then intended to be returned to the client and rendered by the createMapListings function.
The /find page is initially rendered through a GET request to the database via mongodb separate from the below code. However subsequent to initial rendering, I then want to return results dependent on the location provided.
The POST method works fine and the location is posted to the server, with the search results being returned as I can print contents out through the console log.
However, I then want to render the results on the client-side. As mentioned, the results of the search render in the console, but when I attempt to pass through to the client, I can render the data itself (in the form of an array of objects) in the #output div, but the createMapListings function does not seem to catch the data.
In fact, the below function appears to be called but prints out over a thousand rows with the data that should be caught described as 'undefined'. I have tried to use res.render and res.redirect, but in the first case, the view renders in the div (which I suppose is expected) and the redirect fails.
The createMapListings function works fine when a simple GET request is made to the server, for example, for all objects in a collection, using ejs template. However, I think the issue here may be a combination of a POST request and then wanting to pass the results back to the AJAX request using the complete callback.
I apologise if the below code is somewhat obtuse. I’m definitely what you would call a beginner. I appreciate the above functionality may not possible so if there is a better way, I would of course be open to it (res.direct perhaps).
Here is the relevant client side script:
$(document).ready(function(){
$("#geolocate").click(function(){
navigator.geolocation.getCurrentPosition(geolocate, function(){
});
});
});
function geolocate(pos){
var latlonpt = [];
var x = pos.coords.latitude;
var y = pos.coords.longitude;
latlonpt.push(x);
latlonpt.push(y);
var obj = {
userlocation: latitudelongitudept
};
$.ajax({
url: "/find",
type: "POST",
contentType: "application/json",
processData: false,
data: JSON.stringify(obj),
complete: function (data) {
$('#output').html(data.responseText);
$('#infooutput').children().remove();
createMapListings(data.responseText);
}
});
};
function createMapListings(maps) {
for (var i = 0; i < maps.length; i++) {
var url = maps[i]._id;
var fullurl = "<a href='/show?id=" + url + "'>Route</a></div>";
var title = "<div>" + maps[i].title + " - " + fullurl +"";
$('#infooutput').append(title);
};
};
</script>
Here is the relevant route used in a basic express app to handle the post request made by the above .ajax wrapper.
exports.findbylocation = function(req, res) {
console.log(req.body.userlocation);
var userlocation = req.body.userlocation;
Map.ensureIndexes;
Map.find({loc :{ $near : userlocation }}, function(err, maps) {
if (err) {
console.log(err)
}
else {
var jmaps = JSON.stringify(maps);
console.log(jmaps);
res.send(jmaps);
}
});
};
By convention, the data variable name in an $.ajax callback signature refers to the parsed HTTP response body. Since your callback is on complete, we're actually passed the XMLHttpRequest used, by convention called xhr. You rightly grab the responseText property, but this needs parsing to be useful. So long as we take care over our Content-Type's and don't explicitly disable processData, jQuery will do the encoding/unencoding for us - we just deal with objects. This is a good thing, since the transport format isn't usually of any particular importance to the application logic. If we use res.json(maps) in place of res.send(jmaps), we can write our call more simply:
$.ajax({
url: '/find',
type: 'POST',
data: obj,
success: function(data) {},
error: function(xhr, text, err) {}
});
Here data is a Javascript object already parsed and ready to use. We also use a default application/x-www-form-urlencoded request rather than explicitly setting a contentType. This is the same as far as express is concerned: it will just be parsed by urlencoded instead of json.
Assuming you solved your client-sie problem.
As you are using express there is no need for JSON.stringfy,
you can use res.json(maps).