How do you stop Chrome and Opera sorting JSON objects by Index ASC?

JqueryJsonGoogle ChromeOpera

Jquery Problem Overview


I've got a problem.

Using ajax I sent a correctly formed JSON object using:

			$.ajax({
				type: "POST", 
				url: SITE_URL+'/data.php',
				dataType: "json",
				data: { ajax: 1 },
				success: function(data) {
					console.log(data);
				}
			});

However, Opera and Chrome, although receiving the same object, print out the object in an incorrect order, it seems like they both perform a sort by ID number instead of just leaving it alone!

Is there a way to stop this auto sort?

Edit, after finding out it is a sort by index number I'm thinking the best method might be to not use the index for storing the object_id and instead store the id number which I want to order the object by.

However I would still like to know if there is a way to stop the sort.

Thank you

Edit2, I'll just like to note that I'm going to work on a different way of doing this, as I feel like I'm abusing objects with this method. However I'd still like to understand why Opera and Chrome feel it is their right to change the order of my objects IDs:

The problem would be me trying to save processing power, lets say we have people with an ID,

1.John, 2.Frank and 3.Sally. However each of these people have a hight property set (and other things). 1.John.180, 2.Frank.220, 3.Sally.150. To save on processing, my I request the result of people be sorted by their height so I get an array of 2, 1, 3 with their other properties. I JSON this array and send it to the browser.

Now FF will keep the new order People[1] would still be John but in a For n as person loop they'll be out of order.

If I can't get around this I'll just have to not bother sorting at the SQL stage and add extra looping and sorting into an array in the JS stage although I wanted to avoid more stress on the browser as its already a Js heavy page.

Many thanks

Jquery Solutions


Solution 1 - Jquery

Had same problem, followed dmc's solution but just added a space in front of the int value to make it a string.

The advantage of using a space rather than another non numeric character is that the subsequently POSTed value can be used directly in a mySQL search clause without having to remove it again.

Solution 2 - Jquery

Different browsers handle objects in different ways, my fault was to try and use the order I built an object as a reference where I shouldn't.

Solution 3 - Jquery

Changing integer to string didn't work for me (Chrome, jQuery 1.7.1). So to keep the order (yes, it's object abusing), I changed this:

optionValues0 = {"4321": "option 1", "1234": "option 2"};

to this

optionValues0 = {"1": {id: "4321", value: "option 1"}, "2": {id: "1234", value: "option 2"}};

Solution 4 - Jquery

Unless that JSON is an array, rather than an object, there is no standard that says it has to be in a certain order. However, this shouldn't be a problem since you don't need to iterate through the object to get the data, you can simply refer to the property.

Solution 5 - Jquery

Some browsers will sort keys which are int, on the other hand it's very easy to change that to string and later revert, mine solution was to add "i" to key, that made a trick. Works perfectly for each browsers :) Hope that helps :)

Solution 6 - Jquery

I had the same "problem" and did not want to go back and change too much in the code. Figured out that at least Google Chrome only re-sorts numeric indexes. As long as the index is considered a string it will show up in the "intended" order. Could someone please verify this on Opera?

Solution 7 - Jquery

None of the solutions worked for me (Aug 2017). Even if I used a string Chrome and Safari (didnt test other browsers) were still sorting based on the string. What I did instead was concatenate my integer key with value string. e.g

result[string_value + str(integer_key)] = string_value

This way the string is first and the browser is free to sort. Then I used some simple logic to separate the key from the value.

Hope this helps.

Solution 8 - Jquery

I had the same issue with chrome, so frustrating. I send it a certain way, why can't chrome just take my word for it? I get that there's no "standard" way, but if that's the case, why impose your own order??

Anyway, I handled it by turning my objects into arrays, so that

{ 0: "", 2: "Frame", 1: "Masonry" }

became

[[ 0, "" ], [ 2, "Frame" ], [ 1, "Masonry" ]]

Had to change some javascript, but it ended up working perfectly.

Solution 9 - Jquery

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]);
			}

I had a similar issue and posted on https://stackoverflow.com/questions/9379143/jquery-getjson-sorting-the-data-on-chrome-ie/9388366#9388366

Solution 10 - Jquery

You need to trick Google Chrome (and others) into thinking you have a string and not a number. Changing the JSON to {"2423":'abc', "2555":'xyz'} will not work.

I had to use "_2423" and "_2555" as indexes in my object to get it to work.

Further, debugging the output to console.log or using for x in y gave different results as to _.each method (see the underscore framework).

You can see my test/proof in JSFiddle with "_" vs no prefix and the for x in y loop: http://jsfiddle.net/3f9jugtg/1/

Solution 11 - Jquery

I resolved this problem using this code:

$('.edit_district').editable("/moderator/sale/edit_sale/", {
    data   : " {'_7':'10 street', '_9':'9 street', '_11':'park'}",
    type   : 'select',
    submit    : 'OK',
    onblur : 'submit'
});

and in script.php:

...
case "id_district":

$district = Districts::GetDistrictByID(Database::getInstance(), (int)substr($value,1));
			
if($district instanceof District){
    $data["id_district"] = $district->id_district;
    echo $district->title;
}

break;

...

Solution 12 - Jquery

Make your object identifier in the JSON string parameter, it works without automatic sorting.

Solution 13 - Jquery

There are some cases where you will need to use the record id to group things in a post process loop. Putting quotes around the key value will work. Or you can use array_merge on the final array which resets the keys.

$processed_array = array(
  235=>array("id"=>235,"name"=>"Something"),
  27=>array("id"=>27,"name"=>"Something")
);
    
array_merge($processed_array);

A print_r($processed_array); now returns the following:

$processed_array = array(
  0=>array("id"=>235,"name"=>"Something"),
  1=>array("id"=>27,"name"=>"Something")
);

Solution 14 - Jquery

I had the same issue and took me a while to work out what was even causing it, what a pain. I ended up removing ID from the index and used array_push, instead of being:

$section[$s_id]['Type'] = $booktype;

etc. I changed it to

array_push($sections, array('ID'=>$s_id, 
                            'CourseID'=>$courseid, 
                            'SectionName'=>$secname, 
                            'Order'=>$order, 
                            'Created'=>$created, 
                            'Description'=>$desc
                            ));

Which allowed me to keep the ordering from PHP since the new indexs where already in order (0,1,2,3 etc as opposed to 112, 56, 411 etc)

Solution 15 - Jquery

One trick that can help is as follow:

You have to add "i" to key while you prepare your data in for loop, that made a trick. Works perfectly for each browsers.

for Example :

 for(var i=1;i<4;i++){
 
 data[''+i+''+your_random_generatedId+'']  = {"questionText":"","answer":"","options":"",noOfOptions:""};
			   
 console.log(data[''+i+''+your_random_generatedId+'']); // This prints the log of each object inside data 

 }

 console.log(data); // This will print the Object without sorting

Hence your Object will be as follow:

Object {156674: Object, 201705: Object, 329709: Object}

hope this helps :)

Solution 16 - Jquery

I had the same issue, when i added another region and needed to have it sorted a specific way. I added a "sort" field in my database table and the select sorted it as i expected, the raw JSON was as expected, but the select field i populated the data into via AJAX still sorted it by the key (region_id)? My problem was that region_id was an integer, and i solved it by encapsulate the key making it a string instead:

  while($row = $result->fetch_array()) {
    $this->regions["'".$row['region_id']."'"] = $row['region'];
  }

old code was:

  while($row = $result->fetch_array()) {
    $this->regions[$row['region_id']] = $row['region'];
  }

Much more elegant than adding all sorts of chars to the key, just to replace it in the other end.

I hope this helps others to get a cleaner code :-)

Solution 17 - Jquery

In php we had a response with this structure:

{
  "12198882": {
    "orderId": "12198882",
    "orderDate": "2021-10-25 15:40:40",
    "total": "167.91",
    "currency": "EUR"
  },
  "12198824": {
     "orderId": "12198824",
     "orderDate": "2021-10-25 15:35:30",
     "total": "110.00",
     "currency": "EUR"
  }
}

And by following Michail's answer we managed to give a response with this new structure instead:

[  {    "orderId": "12198882",    "orderDate": "2021-10-25 15:40:40",     "total": "167.91",     "currency": "EUR"  },  {    "orderId": "12198824",    "orderDate": "2021-10-25 15:35:30",    "total": "110.00",    "currency": "EUR"  }]

Simply by calling array_flatten() on the value of the previous response, like this:

array_flatten($service->getOrders())

And this solved the issue.

Solution 18 - Jquery

When you pass the data object to console.log, JavaScript will end up calling the toString() method for the data object. Since you don't like the default format of data's toString() method, you'll have to do the work yourself.

You can dump the object's fields yourself if you want that type of control - you'd have to get the keys/fields and sort them and then build the string version yourself.

something like:

for (field in obj)
    add field to array

sort array into whatever order you want

for (field in array)
    get value of field from obj
    create string of field : value, append to main string

console.log(main string)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDorjanView Question on Stackoverflow
Solution 1 - JqueryFarnhamBeeView Answer on Stackoverflow
Solution 2 - JqueryDorjanView Answer on Stackoverflow
Solution 3 - JqueryMichailView Answer on Stackoverflow
Solution 4 - JqueryJames LongView Answer on Stackoverflow
Solution 5 - JquerydmcView Answer on Stackoverflow
Solution 6 - JqueryAlasjoView Answer on Stackoverflow
Solution 7 - Jqueryuser3167654View Answer on Stackoverflow
Solution 8 - Jqueryemery.noelView Answer on Stackoverflow
Solution 9 - JqueryCollectorView Answer on Stackoverflow
Solution 10 - JqueryDynamicDanView Answer on Stackoverflow
Solution 11 - Jqueryuser1039177View Answer on Stackoverflow
Solution 12 - JqueryAlexej NagelView Answer on Stackoverflow
Solution 13 - JqueryNick JohnsonView Answer on Stackoverflow
Solution 14 - JqueryAersolKingView Answer on Stackoverflow
Solution 15 - JqueryMaulikView Answer on Stackoverflow
Solution 16 - JqueryKim Lundberg Stegenborg MadsenView Answer on Stackoverflow
Solution 17 - JqueryGiorgio TempestaView Answer on Stackoverflow
Solution 18 - Jquerytypo.plView Answer on Stackoverflow