2

I have an application using jquery 2.0.3 and a CakePHP 2.x back-end. It's a legacy application, which is why we're using those versions.

Part of the application features a <select id="orderTags"> which when changed fires an ajax request to an endpoint /get_tags. This returns a JSON-encoded response which is then used to update some list items in an element called #tags.

The code to make the request works by listening for changes to #orderTags:

$('#orderTags').change(function() {
    var order = $('#orderTags option:selected').val();
    $("#tags ul").html('');
    get_tags(order);
});

This then executes get_tags() and passes in a string for ordering, which are set as follows:

  1. Order by date added (name: "date")
  2. Order by name ASC (name: "name_asc")
  3. Order by name DESC (name: "name_desc")

I can see in my browser Network tab that requests are being made to the appropriate endpoint - giving a 200 status - and passing in the appropriate string as a $_GET parameter:

  1. /get_tags?orderby=date
  2. /get_tags?orderby=name_asc
  3. /get_tags?orderby=name_desc

When viewing the Response in my Network tab, the endpoint is producing the correct (i.e. different order in each case) JSON. For example the screenshots below so the response from (2) and (3) above, and as you can see the order is alphabetical: enter image description here

enter image description here

I'm using the $.each function in jquery to loop through the response. The following is the code inside get_tags() referenced above:

function get_tags(order) {

   order = order || "date";

   $.ajax({
        url: '/get_tags',
        dataType: 'json',
        data: {'orderby': order},
        cache: false
    }).done(function (data) {
        console.log(data);
        var items = '';

        $.each(data, function (key, val) {
            items += '<li id="tag-' + key + '"><i class="fa-li fa fa-tags"></i>' + val + '</li>';
        });

        $("#tags ul").append(items);

   });

The console.log(data) is giving a different output to the response from the script. I've used cache: false and can see jquery is appending the _ parameter in the URL.

So for example I've posted the console.log output from the above 2 screenshots. The same data - in totally the wrong order - is being presented in each case:

enter image description here

enter image description here

Why is this happening?

3
  • 3
    There is no set ordering of properties in JavaScript objects. If you want a fixed ordering, use an array. Commented Sep 3, 2018 at 11:45
  • Return the JSON in array format? Or use something in the js to handle it as an array inside the ajax .done()? If you know the answer to this or have a link please post a solution. Commented Sep 3, 2018 at 12:03
  • Return an array of objects instead of a single object, or return an adjunct array that has the proper ordering of the property names from the main object. The idea is to have an array involved, because the ordering is intrinsically fixed. Commented Sep 3, 2018 at 12:06

1 Answer 1

2

In case anyone else has the same problem I've found the solution. The problem - as mentioned by @Pointy in the comments - was related to:

There is no set ordering of properties in JavaScript objects. If you want a fixed ordering, use an array

The data is being returned by the /get_tags endpoint using PHP's json_encode functionality.

The solution was to use JSON_FORCE_OBJECT where the output was being produced, i.e.

echo json_encode($output, JSON_FORCE_OBJECT);

Where $output is an array of data that the endpoint should return.

There is more information about why this works here: How do I `json_encode()` keys from PHP array?. It means that the data returned has array keys which are important for preserving the order.

Screenshot Example of the JSON returned for ordering A-Z. Note the array keys highlighted green versus the original screenshots (which lack array keys):

enter image description here

The $.each code needed tweaking slightly as well. This is because key now represents the array key (highlighted in green on the screenshot above) and val is the object of data returned by the endpoint which can be accessed with dot-notation:

$.each(data, function (key, val) {
    items += '<li id="tag-' + val.id + '"><i class="fa-li fa fa-tags"></i>' + val.name + '</li>';
});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.