jQuery: $.getJSON sorting the data on Chrome / IE? - javascript

I'm passing an associative array (id => val) using Ajax and receiving it with jQuery's $.getJSON which read the data properly and prepared the object. There is, however, very annoying sorting issue.
It appears that on Chrome and IE the data becomes sorted by the id part of the associate array. So if the array should be (5=> 'xxx', 3 => 'fff') it actually becomes (3 => 'fff',5=> 'xxx'). On FireFox it works as expected, i.e. not sorted.
Any ideas?

You can add a leading 0 for all integer indexes.
var json = { '05' => 'xxx', '03' => 'fff' };

Seems the best way is to avoid associative arrays at all. When you want to send an associate array simply send it as two separate arrays - one of keys and one of values. Here's the PHP code to do that:
$arWrapper = array();
$arWrapper['k'] = array_keys($arChoices);
$arWrapper['v'] = array_values($arChoices);
$json = json_encode($arWrapper);
and the simple JavaScript code to do whatever you'd like with it
for (i=0; i < data['k'].length; i++) {
console.log('key:' + data['k'][i] + ' val:' + data['v'][i]);
}

Another option is to return the data as an array of objects. That will ensure that the objects stay in the order that you return them.
Edit:
Basically, for each key > value pair, push it to a new array and json_encode that array.

Related

JS: Iterate over an array of objects to update object

I am trying to iterate over an array of array objects to de-dupe and sort the data within each. The function onlyUnique returns unique values in an array. The problem is, it doesn't work as intended.
arr_lists = [arr_1, arr_2, arr_3, arr_4, arr_5, ...]
for (var list_obj of arr_lists) {
list_obj = list_obj.join().split(',').filter(onlyUnique);
list_obj.sort();
Logger.log(list_obj);
}
The logger results show true (i.e. they are what I am looking for), but the original array is unchanged, although I think it should have been updated.
I've tried assigning the filtered array to a new array... nope.
I know that I could add a thousand lines of code to achieve the results, but that seems silly.
I suspect it's something obvious.
You can simply achieve it by using Set data structure to remove the duplicates and Array.sort() compare function to sort the elements in an array.
Live Demo :
const arr_lists = [[2,3,5,6], [7,2,5,3,3], [1,5,3], [4,7,4,7,3], [1,2,3]];
arr_lists.forEach((arr, index) => {
arr_lists[index] = [...new Set(arr)].sort((a, b) => a -b);
})
console.log(arr_lists);

Can not loop JSON object in Javascript

I apologize there is going to be a lot of attachments to explain this.
I am pulling a JSON object, storing it in SQLite, then later retrieve it and trying to compare it with a newer pull to check for updates. This works perfectly in simple, one level JSON. The trouble is with nested JSON.
I console.log the datasets before comparison (the first array(4) is the new set, the second array(4) you see in this picture is the old set, previously retrieved from the Same API, stored in SQLite and then retrieved on future loading
datasets
they look identical and both are valid JSON objects according to jsonlint.com,
I was able to loop through the new JSON and "collapse" it to a single level array so I can use it later to compare. With this code I can see that the "links" array is correct
new links array
newData.forEach(m=>{
console.log('new data loop 1');
Object.entries(m as Record<string, string[]>).forEach(([key, value]) => {
console.log('new data loop 2');
if (key == 'links'){
console.log('new value');
console.log(value);
for (let i=0; i< value.length; i++){
newData2.push(value[i]);
}
// newData2.push(value);
}
})
})
However, when I tried to do the same loop for the old JSON object (stored in SQLite then retrieved), Chrome debugger thinks the "links" array has a length of zero, which from my research it could just mean it is recongzied as an object and therefore no length, never mind it worked fine for the new JSON object.
old links array
The issue:
4. I have no way to loop the old JSON object, here are three different ways to try to loop it and none of them makes into the loop.
oldData.forEach(m2=>{
console.log('old data loop 1');
Object.entries(m2 as Record<string, string[]>).forEach(([key2, value2]) => {
console.log('old data loop 2');
if (key2 == 'links'){
console.log('value');
console.log(value2);
for (var ii=0; ii< value2.length; ii++){
console.log('old data loop 2.1');
}
console.log('old data loop 2.5');
value2.forEach(m3=>{
console.log('old data loop 3');
Object.entries(m3).forEach(([key3, value3]) => {
console.log('old data loop 4');
console.log(key3 + '...' + value3);
});
})
for (var key in value2) {
console.log('old data loop 4');
if (value2.hasOwnProperty(key) ){
console.log( "key:"+key+", val:"+value2[key] );
}
}
}
})
})
The result looks something like this, so you can tell none of the attempts to loop the old "links" object works.
no loop happening
5. so there is obviously something about the old nested JSON object that is causing problems with the looping. I really appreciate any help as I have worked on this off and on for days and can't figure this out. The ultimate goal is to compare the two nested JSON objects so if there are other ways I am open to that too.
I solved this. The problem had nothing to do with how JSON objects is looped. It was an async problem. I did something after I load the array and I forgot to put that in a Promise so that even though Chrome debugger shows me the array had content, in real time it was empty!
Thanks #Serge, I did take your advice and just use string.search function now instead of trying to flatten the arrays manually then compare.

JavaScript FormData Sort Entries (without jQuery)

I have some code that uses jQuery and needs re-writing to use native JS but I am having trouble with one section of it where what it does is:
Obtains the form data
Sorts the keys alphabetically
Loops through the elements to create a new array of items based on the form
This is what works in jQuery:
let formData = $('#TheForm').serialize();
let formItems = formData.split("&");
formItems.sort();
for (const element of formItems) {
//Do stuff here
}
This is what I have so far in native JS that does not yet work:
var theForm = document.getElementById('TheForm');
let formData = new FormData(theForm);
let formItems = formData.entries();
//formItems.sort(); <-- Can't work out a way to do this
for (let [key, value] of formItems) {
//Do stuff here
}
I think once I can figure out a way to sort the entries this will hopefully work and the code in the for loop can be simplified as it is having to extract the key and value on the = sign (from element) currently but in the new version the key and value are already separate.
The reason I am sorting the keys is because this form submits to the Barclays payment system (EPDQ) and requires the form elements to be in alphabetical order and I must also encrypt them, sending both the unencrypted and encrypted values where the server only accepts the data if the encrypted version matches when the remote server performs the same function. Within the loop I am populating both encrypted and unencrypted arrays so it is easier to sort at this point rather than later.
Thanks I really appreciate the help (below).
Since the entries function returns an Iterator, you'll first want to get an Array from that:
const formItems = Array.from(formData.entries())
At this point you have an Array of pairs, each pair being a tuple, an Array where the first element represents the "key" and the second one the "value". This is good though, because you now have an array on which you can call the sort function, that just so happens to be able receive a comparator function!
const sortedItems = formItems.sort(
([leftKey], [rightKey]) => leftKey > rightKey ? -1 : 1
)
The sort function is receiving an arrow function, where the two parameters (the two items being compared) are destructured in order to extract the first value of each of them into a variable - each of them being a pair, an array of two values, this works out just fine.

JS How can I convert a serialized object to an Array?

Using jquery.nestable.min.js, I get a the following output:
[{"id":32},{"id":29},{"id":30}]
This current output is coming from the following code:
const myList = JSON.stringify(list.nestable('serialize'));
I need it to simply be:
32, 29, 30
End result is that I would like to read a normal array in PHP. I'm looking to either convert myList to an array in Javascript and POST that array, or convert the current version of the object to an array inside PHP, whichever is most effective.
I've tried to use json_decode in PHP, but I get empty values. So I figured if I can just convert to a normal Array before sending it off to PHP, then it would be less of a hassle.
Thank you.
This may be duplicated, in which case, please point me to the best answer
Depending on whether you want an array (per your title), or literally 32, 29, 30 per your post:
console.log([{"id":32},{"id":29},{"id":30}].map(i => i.id))
console.log([{"id":32},{"id":29},{"id":30}].map(i => i.id).join(', '))
Which, with your example, is probably going to be:
const myList = JSON.stringify(list.nestable('serialize').map(i => i.id));
If you just want an array of numbers, convert that output array of objects to array of numbers
var list = [{"id":32}, {"id":29}, {"id":30}];
var required = list.map(item => item.id);
console.log(required);

Sorting a dynamically filled array of objects

I have an array that is initialized like such var generationObject = [{string:"", score: 0}];
which I then fill dynamically:
for(var i = 0; i < amount_offspring; i++)
{
// "load" text into array and send the string to see if it evolves
generationObject[i].string = evolve(start_text, characters, mutation_rate);
// then score the string
generationObject[i].score = score(target_text, generationObject.string);
}
I then want to sort this array by score. I don't know what's best, to sort it in the for loop or sort the entire array afterwards.
I will then take the string of the highest scoring object and pass it through the function again, recursively.
So what would be a good way to go about this sort function? I've seen some here use this
generationObject.sort(function(a, b) {
return (a.score) - (b.score);
});
But I'm not sure if .sort is still supported? This didnt seem to work for me though.
generationObject is an array, not an object, so score(target_text, generationObject.string); could be the problem, as .string will be undefined. (Did you mean generationObject[i].string?)
Try building your array like this:
var generationObject = []
for(var i = 0; i < amount_offspring; i++)
{
evolved_string = evolve(start_text, characters, mutation_rate)
generationObject.push({
string: evolved_string,
score: score(target_text, evolved_string)
})
}
And then Array.prototype.sort should do the trick.
You should write your sorting logic outside the for loop, since if you put it inside, the object array will be sorted N times, where N being the iterations of your loop. The following are two ways to do it-
By using sort() function- To clarify your question, sort() is still supported across almost all the browsers. If you are still concerned about the browser compatibility, you can check the MDN documentation to see the list of supported browsers.
generationObject = generationObject.sort(function(a, b) {
return parseInt(a.score) - parseInt(b.score);
});
By using underscorejs-
In underscore, you can take advantage of the sortBy() function.
Returns a (stably) sorted copy of list, ranked in ascending order by the results of running each value through iteratee. iteratee may also be the string name of the property to sort by (eg. length).
You can simply do this in underscorejs-
generationObject = _.sortBy(generationObj, 'score');

Categories