Django/Ajax/Javasdript JSON.parse convert string to JavaScript object - javascript

I am using Ajax to to send a get request from the sever, i am querying and getting a particular product from the product model, i want to return result as JavaScript objects but its return this '{' as i try to access the first value from the responseText[0]. How can i convert data return to js object.
here is my code
views.py
def edit_product(request):
product_id = request.GET.get('product_id')
print('THIS IS PRODUCT ID ', product_id)
product = Product.objects.get(pk=product_id)
data = [
{
'name':product.name,
'brand':product.brand,
'price':product.price,
'description':product.description
}
]
return HttpResponse(data)
ajax.js
function getProductEditId(product_id){
//alert(id)
document.getElementById('gridSystemModalLabel').innerHTML='<b> Edit product </b>';
//change modal header from Add product to Edit product
var request = new XMLHttpRequest();
request.open('GET', '/edit_product/?product_id=' + product_id, true);
request.onload = function(){
console.log('hello world', product_id)
//var data = request.responseText
var data = JSON.parse(JSON.stringify(request.responseText));
console.log(data[0])
}
request.send();
}

A HTTP response can not contain a dictionary, you can pass data through a specific format, like for example JSON. Django offers some convenience for that with the JsonResponse [Django-doc]:
from django.http import JsonResponse
def edit_product(request):
product_id = request.GET.get('product_id')
print('THIS IS PRODUCT ID ', product_id)
product = Product.objects.get(pk=product_id)
data = [
{
'name':product.name,
'brand':product.brand,
'price':product.price,
'description':product.description
}
]
return JsonResponse(data, safe=False)
But as the code hints, this is not safe, since an array at the root level was a famous JSON hijacking exploit.
It is typically better to just pass a dictionary (so no list), and then the safe=False parameter can be removed. Although it is not really "safe" to then just assume that all security exploits are gone.
Alternatively, you can use json.dumps [Python-doc] (which is more or less what JsonResponse does internally), but then you thus will probably end with duplicate code.
At the JavaScript side, you then only need to parse the JSON blob to a JavaScript object:
//change modal header from Add product to Edit product
var request = new XMLHttpRequest();
request.open('GET', '/edit_product/?product_id=' + product_id, true);
request.onreadystatechange = function() {
console.log('hello world', product_id)
if(this.status == 200 && this.readyState == 4) {
var data = JSON.parse(this.responseText);
console.log(data[0])
}
}
It is also not very clear to me why you encapsulate the data in a list here: if the response always contains one element, it makes more sense to just pass the dictionary.

Related

How to to access Ajax POST request from Javascript in Django

I am sending an Ajax POST request to Django from a Javascript modal. The csrf token is included correctly (after much headache...) but for whatever reason, I cannot 'fetch' the request data in my views.py. I have added some comments in the code to indicate what seems to be working
I have been reading everything I could find on this, but still couldn't find the error so any input would be highly appreciated. Thanks!
Javascript
function getMenuItem(id){
console.log(id); // menuitem id prints correctly
// Open request to get menuitem
const request = new XMLHttpRequest();
request.open('POST', '/menuitem');
// Include csrf token in header so Django will accept the request
const header = "X-CSRFToken"
const token = Cookies.get('csrftoken'); // Using the js-cookie library
console.log(token); // token prints correctly
request.setRequestHeader(header, token);
// Send request
request.send(id);
//Once request is received parse it and insert result in DOM
request.onload = () => {
const received = request.responseText;
console.log(received); // Prints the debug message from Django
const parsed = JSON.parse(received);
document.getElementById('menuItem').innerHTML = parsed;
};
};
views.py
def menuitem(request):
if request.method == 'POST':
id = request.body # I have also tried HttpRequest.body
print(id) # Does not print
menuitem = MenuConfiguration.objects.filter(id=id).all()
menuitem = serializers.serialize('json', menuitem)
menuitem = json.loads(menuitem)
return menuitem
Traceback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/utils/deprecation.py", line 93, in __call__
response = self.process_response(request, response)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/middleware/clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'list' object has no attribute 'get'
[11/Apr/2019 06:10:18] "POST /menuitem HTTP/1.1" 500 54835
I made it work with the below adjustments, so now the request is sent correctly and processed by Django and the query result is received by the JS. I had to make a slight hack to remove [] from the response text object in order to enable JSON.parse to process it.
I have a new problem though, which is; getting the values of foreign keys included in the query (i.e. not just the keys as it is the case now). I will post a separate question about that, but please leave a comment if you have a solution for this off the cuff
Javascript
function getMenuItem(id){
console.log(id);
// Open request to get menuitem
const request = new XMLHttpRequest();
request.open('POST', '/menuitem');
// Include csrf token in header so Django will accept the request
const header = "X-CSRFToken";
const token = Cookies.get('csrftoken'); //Using the js-cookies library
request.setRequestHeader(header, token);
// Formdata object to structure data as if submitted from a form
const data = new FormData();
data.append('id', id);
// Send request
request.send(data);
console.log("Request sent");
//Once request is received parse it and insert result in DOM
request.onload = () => {
const received = request.responseText;
console.log("Data as received: " + received);
// Remove [] from response text
removedfirst = received.substring(1);
removedlast = removedfirst.substring(0, removedfirst.length-1);
console.log("Data with [] removed: " + removedlast);
// Parse to JS object
const parsed = JSON.parse(received);
console.log("Output of JSON.parse:");
console.log(parsed);
// Insert value into DOM
document.getElementById('outputField').innerHTML = parsed[0].fields.base;
};
};
views.py
def menuitem(request):
if request.method == 'POST':
# Get product id from request
id = request.POST.get('id')
# Retrieve data for specific product id
menuitem = MenuConfiguration.objects.filter(id=id).all()
# Turn query response into JSON
data = serializers.serialize('json', menuitem)
# Return a HttpResponse containing the JSON data
return HttpResponse(data, content_type='application/json')
Output from JS console:
console logs
There's a few things to address here.
In your Javascript code you should send the id value correctly encoded as a form parameter using the key=val syntax:
request.send("id=" + id);
Then in your view, you should retrieve the value from the POST dictionary:
if request.method == 'POST':
id = POST['id'] # Retrieve the value of the id parameter
Lastly your view must return an HttpResponse. Since you're looking to return JSON, you should pass that into the HttpResponse and set the content_type argument to application/json:
if request.method == 'POST':
id = POST['id']
menuitem = MenuConfiguration.objects.filter(id=id).all()
data = serializers.serialize('json', menuitem)
# Return a HttpResponse containing the JSON data
return HttpResponse(data, content_type='application/json')

How do i correctly format parameters passed server-side using javascript?

I cannot figure out how to get the following code working in my little demo ASP.NET application, and am hoping someone here can help.
Here is the javascript:
function checkUserName() {
var request = createRequest();
if (request == null) {
alert("Unable to create request.");
} else {
var theName = document.getElementById("username").value;
var userName = escape(theName);
var url = "Default.aspx/CheckName";
request.onreadystatechange = createStateChangeCallback(request);
request.open("GET", url, true);
request.setRequestHeader("Content-Type", "application/json");
//none of my attempts to set the 'values' parameter work
var values = //JSON.stringify({userName:"userName"}); //"{userName:'temp name'}"; //JSON.stringify({ "userName":userName });
request.send(values);
}
}
Here is the method in my *.aspx.cs class:
[WebMethod]
[ScriptMethod(UseHttpGet=true)]
public static string CheckName(string userName)
{
string s = "userName";
return s + " modified backstage";
}
When this code runs I receive this exception:
---------------------------
Message from webpage
---------------------------
{"Message":"Invalid web service call, missing value for parameter: \u0027userName\u0027.","StackTrace":" at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary`2 parameters)\r\n at System.Web.Script.Services.WebServiceMethodData.CallMethodFromRawParams(Object target, IDictionary`2 parameters)\r\n at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams)\r\n at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.InvalidOperationException"}
---------------------------
OK
---------------------------
I started searching here, then went on to several threads on SO, trying quite a few combinations of quotation marks and key-value pairs, but nothing I've tried has worked.
When I remove the parameter from the C# method and request.send(), I get a response in my JS callback that I can work with. But as soon as I try to do something with parameters, I get the above exception. I'd like to know how to do this without using jQuery, if possible.
Thanks in advance.
FINAL VERSION
Using Alexei's advice, I ended up with the following, which works. The URL was missing the apostrophes on either end of the parameter value; this was keeping the call from going through.
function checkUserName() {
var request = createRequest();
if (request == null) {
alert("Unable to create request.");
} else {
var theName = document.getElementById("username").value;
var userName = encodeURIComponent(theName);
var url = "Default.aspx/CheckName?name='" + theName + "'";
request.onreadystatechange = createStateChangeCallback(request);
request.open("GET", url, true);
request.setRequestHeader("Content-Type", "application/json");
request.send();
}
}
request.send(values);
This won't work with a "GET". Try
request.open("POST", url, true);
http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp
You need to:
decide whether you want GET or POST. For GET request you need all parameters to be in Url (and body to be empty), for POST you can use both. As of current code you are expecting GET, but sending POST.
properly add query parameter - name and encoded value. encodeUriComponent is JavaScript function of choice, see Build URL from Form Fields with Javascript or jquery for details
if using POST you need to properly encode parameters there too as well specify correct "content-type" header.
if sending JSON you need to decode JSON server side.
Alternatively you can use hidden form to perform POST/GET as covered in JavaScript post request like a form submit
Side note: jQuery.ajax does most of that for you and good source to look through if you want to do all yourself.
Like Alan said, use the POST method. Or pass your arguments in your URL before opening it, e.g.
var url = "Default.aspx/CheckName?userName=" + values;
EDIT : no, it's probably a bad idea since you want to send JSON, forget what I said.
If you need to go for POST, then you need to send it like this.
var values = JSON.stringify({"'userName':'"+ userName+ "'"});
And you have to change HttpGet to HttpPost
Given that your server side method asks for GET, you need:
request.open("GET", url + "?username=" + userName, true);
request.send();
The works for me:
function checkUserName() {
var request = new XMLHttpRequest();
if (request == null) {
alert("Unable to create request.");
} else {
var userName = "Shaun Luttin";
var url = '#Url.RouteUrl(new{ action="CheckName", controller="Home"})';
request.onreadystatechange = function() {
if (request.readyState == XMLHttpRequest.DONE ) {
if(request.status == 200){
document.getElementById("myDiv").innerHTML = request.responseText;
}
else if(request.status == 400) {
alert('There was an error 400')
}
else {
alert('something else other than 200 was returned')
}
}
}
request.open("GET", url + "?username=" + userName, true);
request.send();
}
}
With this on the server side:
[HttpGet]
public string CheckName(string userName)
{
return userName + " modified backstage";
}

XMLHttpRequest send JS Object

I'm trying to send an JS Object with an (POST) XMLHttpRequest, but I get no POST data in PHP.
This code worked before with an Ajax request, but i'm trying to get feedback from the server for an progressbar ( whitch is working fine now). That's why i've chagend to XMLHttpRequest.
The code:
var dataRows = {
'bewaarnaam': bewaarNaam,
rows: {}
};
$(".rows").each(function (i, obj) {
var row = $(obj);
var rowName = $(row).attr('name');
var chests = {};
$(".cv_chest", row).each(function (i2, obj2) {
chests[$(obj2).attr('id')] = {
'counter': $(obj2).attr('chest_counter'),
'height': $(obj2).attr('chest_height'),
'db_id': $(obj2).attr('db_id')
};
});
var top = $(row).css('top').replace("px", "");
var left = $(row).css('left').replace("px", "");
var rowData = {
'name': $(row).attr('name'),
'x': parseInt(left),
'y': (parseInt(top - 100)),
'rotation': rotation[$(row).attr('dir')],
'db_id': $(row).attr("db_id"),
'chests': chests
};
dataRows.rows[$(row).attr('id')] = rowData;
});
...
var xhr = new XMLHttpRequest();
xhr.open("POST", "{{ url('bewaarplaatsen/xhrTest/') }}", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(dataRows);
So my question is rather simple... How can i send an object with an post through the XmlHttpRequest function?
Use JSON:
var xhr = new XMLHttpRequest();
xhr.open("POST", "{{ url('bewaarplaatsen/xhrTest/') }}", true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.send(JSON.stringify(dataRows));
EDIT:
You can also use newer fetch API, see Fetch: POST JSON data.
You can't. "An object" is a data structure that exists in memory and only makes sense to the program it is dealing with it.
You need to serialise the data (e.g. using the application/x-www-form-urlencoded format, or JSON, or XML, or a host of other choices) and send that instead.
If you are trying to send entire DOM elements (and it isn't clear what the data you are trying to send actually is) then serialising them would involve converting them to HTML or (and this would usually be the better option) a data structure that they represent.

pass array in javascript .send function

This is regarding passing an array to a php page.Is it possible to send an array like this(code below)? if its not possible , what changes should i bring about to my code?
function ajax_post(){
var hr = new XMLHttpRequest();
hr.open("POST", "get_numbers.php", true);
hr.setRequestHeader("Content-type", "application/json");
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var data = JSON.parse(hr.responseText);
var results=document.getElementById("ace");
//results.innerHTML=data.u1.port;
for (var obj in data)
{
results.innerHTML+=data[obj].port;
}
}
}
var cards= new Array();
cards[0]="hearts";
cards[1]="spades";
hr.send(cards);
results.innerHTML = "processing...";
}
.send() doesn't take a javascript array. There are a number of forms of data you could send and you will have to decide which form is appropriate, but an array is not one of them. The simplest would be to turn the array into a JSON string and send that.
var cards = [
"hearts",
"spades"
];
hr.send(JSON.stringify(cards));
Then, on the receiving end of things, you would parse the JSON back into whatever language form you are using on the server end. If it's PHP, then you can use the PHP functions for parsing the JSON which will put the data into a PHP array on your server.
Per the MDN doc page for the XMLHttpRequest object, .send() can take the following types of data:
void send();
void send(ArrayBufferView data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
Using JSON would be using the string type.

How to pass all the params as a single object while making ajax call

I have the below js code:
xmlhttp = GetXmlHttpObject();
if (xmlhttp != null) {
var url = "/support/residential/outage/serviceOutage?cbrnum=" + cbrnum + "&btn=" + btn + "&outagetkt=" + outagetkt;
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("thankyoucontent").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST", url, true);
xmlhttp.send(null);
}
This calls a servlet by passing certain params in query string. Now my question is , can we bind all the params into a single object , send that object alone in query string and use the object in the servlet to retrieve the param values? Is it possible?
Yes, you can send the data as JSON to the server:
var data = {cbrnum: cbrnum, btn: btn};
var url = "...?data=" + encodeURIComponent(JSON.stringify(data));
Then on the server side, retrieve the value of data and parse the JSON into native data types (Converting JSON to Java).
Note though that browsers often impose a length limit on the URL. If you have a lot of data, do a POST request instead.

Categories

Resources