JavaScript automatically sorts dict? - javascript

So, the problem is that when ajax script receives dictionary from server it gains different order:
Server sent this:
{753: 'Wraith', 752: 'Phantom Extended', 751: 'Phantom', 750: 'Ghost Extended', 749: 'Ghost', 748: 'Dawn', 747: 'Cullinan', 746: 'Black Badge'}
But client gets this:
{746: "Black Badge", 747: "Cullinan", 748: "Dawn", 749: "Ghost", 750: "Ghost Extended", 751: "Phantom", 752: "Phantom Extended", 753: "Wraith"}
Js:
$.ajax({
method: 'GET',
url: request_url,
success: function(data){
console.log(data.response_models);
...
Also, the server is running on Django
Please help! I really appreciate it

If your object has properties that are "indexes" (numeric strings in range 0 .. 2^32-1), these properties are always enumerated is sorted numeric order. There's no way you can change that.
Have your server app return data in a more reasonable format, like an array of number-string pairs or an array of objects {id, value}. If this is not possible, convert your object to the said format on the client side, for example:
response = {753: 'Wraith', 752: 'Phantom Extended', 751: 'Phantom', 750: 'Ghost Extended', 749: 'Ghost', 748: 'Dawn', 747: 'Cullinan', 746: 'Black Badge'}
dataToDisplay = Object.entries(response).sort(
([key1, val1], [key2, val2]) =>
val1.localeCompare(val2))
console.log(dataToDisplay)

Related

Unable to access JSON data from Javascript

I am passing the following from my Django back-end to my front-end in order to dynamically build a form :
{
"access_key": "93ec6137de00eacee6f8",
"profile_id": "7851E15D64",
"transaction_uuid": "c878c7e6db5657526",
}
Within the browser console, if I pass :
MyJSON = {
"access_key": "93ec6137de00eacee6f8",
"profile_id": "7851E15D64",
"transaction_uuid": "c878c7e6db5657526",
}
Then I can access each value properly, for example, MyJSON.access_key returns 93ec6137de00eacee6f8 perfectly within the console.
However, from my Javascript, I am unable to access any of those values as i get an "undefined".
var obj = JSON.parse(MyJSON)
console.log(obj) // returns the whole JSON String
console.log(typeof(obj)) // returns 'string'
alert(obj[0]) // returns "{", the very first character of the 'string'
alert(obj.access_key) // returns "undefined".
- How can access each Key and Value from MyJSON from my javascript? (not JQuery)
Note that I have reviewed many similar article but I must be missing the obvious ...
Hope you can assist !
Thanks in advance.
EDIT :
I have a list of Fields and a list of Values which i then merge into the below (pass the JSON Validator on https://jsonlint.com/):
{'access_key': '93ec6137d70aada23400eacee6f8', 'profile_id': '7851E53E-96BB-4D4-BD5-0FE61CC15D64', 'transaction_uuid': '00939a90-db7b-41cb-af45-669ec5cc69e8', 'signed_field_names': 'bill_to_forename,bill_to_surname,bill_to_email,bill_to_phone,bill_to_address_line1,bill_to_address_city,bill_to_address_postal_code,bill_to_address_country,transaction_type,reference_number,payment_method,amount,currency,locale,card_type,card_number,card_expiry_date', 'unsigned_field_names': 'card_type,card_number,card_expiry_date', 'signed_date_time': '2021-05-23T16:20:17Z', 'bill_to_forename': 'John', 'bill_to_surname': 'Doe', 'bill_to_email': 'null#cfgfg.com', 'bill_to_phone': '07922889582', 'bill_to_address_line1': '123 Random Street', 'bill_to_address_city': 'London', 'bill_to_address_postal_code': 'RG1T3X', 'bill_to_address_country': 'GB', 'transaction_type': 'sale', 'reference_number': 'o6yejf', 'payment_method': 'card', 'amount': '100', 'currency': 'USD', 'locale': 'en', 'card_type': '001', 'card_number': '4456530000001096', 'card_expiry_date': '12-2026', 'signature': 'Un5gNYB5qZaRazzCDWqrdZuNkTRARIcfAt9aF2a1wbY='}
Back-end Code
FieldList = ['access_key', 'profile_id', 'transaction_uuid', 'signed_field_names', 'unsigned_field_names', 'signed_date_time', 'bill_to_forename', 'bill_to_surname', 'bill_to_email', 'bill_to_phone', 'bill_to_address_line1', 'bill_to_address_city', 'bill_to_address_postal_code', 'bill_to_address_country', 'transaction_type', 'reference_number', 'payment_method', 'amount', 'currency', 'locale', 'card_type', 'card_number', 'card_expiry_date', 'signature']
ValueList = ['93ec6137d0aada23400eacee6f8', '7851E53E-96BB-4DF4-BD55-0FE61CC15D64', 'c4fe96b0-063f-4b94-a6a5-2137bb796bd9', 'bill_to_forename,bill_to_surname,bill_to_email,bill_to_phone,bill_to_address_line1,bill_to_address_city,bill_to_address_postal_code,bill_to_address_country,transaction_type,reference_number,payment_method,amount,currency,locale,card_type,card_number,card_expiry_date', 'card_type,card_number,card_expiry_date', '2021-05-23T16:27:24Z', 'John', 'Doe', 'null#cyrce.com', '07922889582', '123 Random Street', 'London', 'RG1T3X', 'GB', 'sale', 'xl42fn', 'card', '100', 'USD', 'en', '001', '4456530000001096', '12-2026', 'vvb73h0GUpzUrvoG9VDaMc3vQRV5GsL4QTATc7IrrPA=']
NewFormat = dict(zip(FieldList, ValueList))
MyJSON = json.dumps(NewFormat, indent=4)
return JsonResponse(MyJSON, safe=False)
Apologies for the large amount of data.
I am somehow forced to use "safe=False" in my Python back-end otherwise I end up with :
Traceback (most recent call last):
File "/home/pi/.local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/pi/.local/lib/python3.7/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/pi/Documents/Droplet/Droplet/Harness/sasop2.py", line 543, in signsasop
return JsonResponse(FinalJSONObject)
File "/home/pi/.local/lib/python3.7/site-packages/django/http/response.py", line 561, in __init__
'In order to allow non-dict objects to be serialized set the '
TypeError: In order to allow non-dict objects to be serialized set the safe parameter to False.
Since I am passing safe=False, is that why my front-end does not get the MyJSON as... JSON?
Would this be the root cause of the issue?
Front-End Sample :
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
// Print received data from server
console.log('%c Processed Data \n',
'background: #000000; color: #FFFFFF; font-size: 30px'
,xhr.response);
// Dynamically create the ReconstructedForm
RawProcessedData = xhr.response
console.log(RawProcessedData)
// Convert to JSON
var obj = JSON.parse(RawProcessedData)
console.log(obj)
console.log(typeof(obj))
alert(obj[0])
alert(obj.access_key)
Thanks a lot for your quick input !
As per deceze's answer, I was essentially double parsing both in the back and front end for no reasons.
Removing the json.dumps from the backend allows the JSON object to be passed and managed in the front end without issue.
I have the same issue when i started developing on Django. If you need to pass dictionarys from django to javascripts, the best thing to do is just using django rest framework. It serialize ( in other words, it transform any data into a dictionary/json ) any given data from a model.
But if you want to make this without Django Rest, you should use fetch on javascript. This fetch ( also called as a "Promise") communicate with the backend ( in this case, Django ) and it GET or POST data from the frontend. I will give you an example.
Supose you have this on views.py:
from django.http.response import JsonResponse
def getJSON(request):
MyJSON = {
"access_key": "93ec6137de00eacee6f8",
"profile_id": "7851E15D64",
"transaction_uuid": "c878c7e6db5657526",
}
return JsonResponse(MyJSON)
And the you can link that to the urls.py like this:
urlpatterns = [
path('get-json', views.getJSON, name="get-json")
]
Then you can GET that JSON by doing this on your javascript:
function getDataJson(){
let url = 'get-json'
fetch(url,{
headers: {
"Content-type": "application/json",
},
})
.then(response => response.json())
.then(data=> console.log(data))
}
This will console log your data.

JSON in client different from JSON returned by Rails server

I am making an AJAX call to this controller method:
def search_posts
keyword = params[:keyword]
results = #client.query("SELECT *
FROM posts
WHERE keyword = '#{keyword}'")
posts = []
results.each do |row|
posts << {
media_id: row["media_id"],
media_type: row["media_type"],
caption: row["caption"]
}
end
#client.close
render json: posts
end
and my JavaScript looks like this:
$.ajax({
url: '/search_posts',
type: "get",
data: {
keyword: keyword
},
success: function(res) {
console.log(res);
}
});
However, when I console.log the returned JSON, some of the media_ids are one less than the real value. For example, a media_id that should be 17924518156307537 is logged in the browser as 17924518156307536.
I have puts'd the posts hash just before the render json: line and the media_ids are correct at that point. What's very strange is that it only happens to some media_ids, not all.
Finally figured it out: JavaScript only supports up to 53-bit integers and some of the media_ids were larger than that. Solved this by converting the media_ids to strings in Ruby before sending them to the client.

Parse Array of JSON objects in NodeJS

I am wondering how can I parse Array of JSON objects in NodeJS?
I want to post JSON array to the server, and be able to use the received array as a regualar JavaScript array.
Thanks in advance.
This is my front-end part that I am converting Array to String using stringify function
document.getElementById("sendJson").addEventListener("click", function () {
$.post("/echo", JSON.stringify(QuestionsArray), function (data) {
alert(data);
});
})
This my back-end part that I am trying to convert Array of JSON object to Array
app.post('/echo', function (req, res) {
var Array = JSON.parse(JSON.stringify(req.toString()));
res.end(Array[0]["QuestionText"].toString());
});
This is Array that I am trying to sent to the server:
[
{
"QuestionText":"What is your Name",
"QuestionType":1
},
{
"QuestionText":"Where are you from",
"QuestionType":2,
"ChoiceList":[
"US",
"UK"
]
},
{
"QuestionText":"Are you married",
"QuestionType":3,
"ChoiceList":[
"Yes",
"No"
]
}
]
Here is the source code
In your app.js:
var bodyParser = require("body-parser");
...
app.use(bodyParser.urlencoded({extended: true}));
Then you can just use req.body to get the posted values:
app.post('/echo', function (req, res) {
var Array = req.body.data;
res.end(Array[0]["QuestionText"].toString());
});
In front-end, don't do any stringifying:
$.post("/echo", {data: QuestionsArray}, function (data) {
alert(data);
});
I'll try to explain this. First of all, you are crating a json string on the client.
JSON.stringify(QuestionsArray)
Then on the server, you are doing the same again:
JSON.stringify(req.toString()) // this is not needed
Then you parse the double stringifyed json string to a javascript object:
JSON.parse(JSON.stringify(req.toString()))
So now you actually have to parse it twice :). If you just stringify it on the server as you are now, and just call:
var arr = JSON.parse(req.toString());
You will get a javascript object that you can access like this:
res.end(arr[0].QuestionText.toString());
Have a look at this jsFiddle and open your developer tools. Look at the console when it runs and you will see where the problem is: example
You may actually send the JSON directly to server.
$.ajax({
url: "/echo",
type: 'POST',
data: JSON.stringify(QuestionsArray),
processData: false,
contentType: 'application/json'
}).success(function (data) {
alert(data);
});
And in node.js, use bodyParser.json to get it back.
app.use(bodyParser.json({}));
app.post('/echo', function (req, res) {
var array = req.body;
res.end(array[0]["QuestionText"].toString());
});
By the way, do not use Array as variable name because Array represent the Array class used by JavaScript and your code has overwritten it.

Typeahead and Bloodhound shows unrelated suggestions when 'remote' is used

When using Typeahead/Bloodhound with a remote option, when the local/prefetch results are under the "limit" (5) the suggestions shown are not related to the input. Looks likes its just showing from the top of the results set up to 5.
Photo: 'Love' is the expected result, everything else is unrelated:
My code:
var keywords = [
{"value": "Ambient"}, {"value": "Blues"},{"value": "Cinematic"},{"value": "Classical"},{"value": "Country"},
{"value": "Electronic"},{"value": "Holiday"},{"value": "Jazz"},{"value": "Lounge"},{"value": "Folk"},
{"value": "Hip Hop"},{"value": "Indie"},{"value": "Pop"},{"value": "Post Rock"},{"value": "Rock"},{"value": "Singer-Songwriter"},{"value": "Soul"},
{"value": "World"},{"value": "Happy"},{"value": "Sad"},{"value": "Love"},{"value": "Angry"},
{"value":"Joy"},{"value": "Delight"},{"value": "Light"},{"value": "Dark"},{"value": "Religious"},{"value": "Driving"},
{"value":"Excited"},{"value": "Yummy"},{"value": "Delicious"},{"value": "Fun"},{"value": "Rage"},
{"value":"Hard"},{"value": "Soft"}
];
// Instantiate the Bloodhound suggestion engine
var keywordsEngine = new Bloodhound({
datumTokenizer: function (datum) {
return Bloodhound.tokenizers.whitespace(datum.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: keywords,
remote: {
url: '/stub/keywords.json',
filter: function (keywords) {
// Map the remote source JSON array to a JavaScript object array
return $.map(keywords, function (keyword) {
return {
value: keyword.value
};
});
}
},
prefetch: {
url: '/stub/keywords.json',
filter: function (keywords) {
// Map the remote source JSON array to a JavaScript object array
return $.map(keywords, function (keyword) {
return {
value: keyword.value
};
});
}
}
});
// kicks off the loading/processing of `local` and `prefetch`
keywordsEngine.initialize();
$('#keyword-search-input').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'keyword',
displayKey: 'value',
// `ttAdapter` wraps the suggestion engine in an adapter that
// is compatible with the typeahead jQuery plugin
source: keywordsEngine.ttAdapter()
});
Upon further research, I think I need to filter remote suggestions manually, according to this thread on the Github Issues for Typeahead.js:
"So the idea is I guess that the data returned from remote should already be filtered by the remote, so no further filtering is done on that."
https://github.com/twitter/typeahead.js/issues/148
I wish to go more in deep on this question for future references. Bear in mind that I am not a JavaScript expert or any expert for that matter. With the Bloodhound engine it does not accommodate constant dynamic interactions with the search parameter for a remote url. Because of this, if you are using some json file, the typeahead search box will only display the limit. So if limit: 10 then the first 10 records of the json data will be displayed, and the result will not change despite the user typing. Only the the first record of the json will have a suggestion based on user prompts which is trivial.
However if the remote source has a query(eg fire query) that gets the required results as in this example, then the search box will be filled with the relevant results each time the search box is populated.
So what if you have a large json file, which you generated from some database, and rather not use prefecth? Obviously for speed and efficiency you will need to use remote. Using php script you would need to do something like:
$key=$_GET['key'];
$con=mysqli_connect("localhost","root","");
$db=mysqli_select_db($con, "database_name");
$query=mysqli_query($con, "SELECT * FROM table WHERE column LIKE '%{$key}%'");
$rows=array();
while($row=mysqli_fetch_assoc($query))
{
$rows[] = $row;
}
echo json_encode($rows);
Here you are getting the value of the search parameter using GET, and you have formed a connection with the database hence your search pool will always be hydrated with "relevant results" upon user prompts.

How to post JSON array of objects using JQuery

I am using Javascript/jQuery in the Chrome browser console to post data to a page. (I'm doing this in Shopify admin, because it doesn't have the capability to bulk import shipping rates).
This is the code I am using:
make_weight_based_shipping_rate(8267845, 98, 99, 'Test Shipping Rate', 59);
function make_weight_based_shipping_rate(cid, minWeight, maxWeight, name, price) {
$.post('/admin/weight_based_shipping_rates.json', {
weight_based_shipping_rate: {
country_id: cid,
name: name,
offsets: [{disabled:true, offset:0, province_id:145570341}, {disabled:true, offset:0, province_id:145570345}],
weight_high: maxWeight,
weight_low: minWeight,
price: price
}
});
}
It works well, except for one line of my request which has an array of objects - the line that begins with 'offsets'.
If I only have one JSON object on this line, and not in an array (by excluding the square brackets), this code works. However, as an array, Shopify comes back with the error '422 (Unprocessable Entity)' and in the body of the response it says '{"errors":{"shipping_rate_offsets":["is invalid"]}}'.
Am I formatting this JSON object incorrectly? If not, is there some other way I can achieve this rather than use the JQuery Post method?
I eventually figured it out. By default, JQuery POST and AJAX requests are encoded as "application/x-www-form-urlencoded". This works most of the time, but it seems to fail when it gets an array such as 'offsets'.
To get around this, first I had to use the JSON.stringify() function on the data being submitted. Then prior to making the POST, I used the ajaxSetup() function to set the content-type to "application/json". My modified code is now:
make_weight_based_shipping_rate(8267845, 98, 99, 'Test Shipping Rate', 59);
function make_weight_based_shipping_rate(cid, minWeight, maxWeight, name, price) {
$.ajaxSetup({
contentType: "application/json; charset=utf-8"
});
$.post('/admin/weight_based_shipping_rates.json', JSON.stringify({
weight_based_shipping_rate: {
country_id: cid,
name: name,
offsets: [{disabled:true, offset:0, province_id:145570341}, {disabled:true, offset:0.00, province_id:145570345}],
weight_high: maxWeight,
weight_low: minWeight,
price: price
}
}));
}
I hope this helps others.

Categories

Resources