Monday, 6 January 2014

JSON object versus array gotcha

Pulled a little of what's left of my hair out with this little gotcha looking at an issue with Umbraco.

I was looking to add a small feature to allow you to re-order a list.  Umbraco (version 7) uses angularjs in the back-office.  Updating this controller and view code was very straightforward to add a couple of buttons to move the list items up and down.  However although I could see the order was properly being saved to the database, the retrieved list remained in the order that the items were created.

Using the Chrome console network tab I could see that the JSON response was coming back from the server in the correct order:

... key":"items","value":{"10":"aaa","7":"bbb","8":"ccc"} ...

However as soon as this materialised in code, the order was lost:

... key":"items","value":{"7":"bbb","8":"ccc","10":"aaa"} ...

The reason for loss of hair was that I was sure that somewhere in the code I'd find that the order was being changed, but it wasn't this.  It was because the JSON is being structured as an object rather than an array, and it seems that if you do this, you can't guarantee that the order of the elements would be the same.

Ideally this would be changed to an array, but a less instrusive change for a code base that's obviously not my own was to add the sort order to the object:

... key":"items","value":{"10": {"value":"aaa","sortOrder":1}, "7":  {"value":"bbb","sortOrder":2},"8":  {"value":"ccc","sortOrder":3}} ...

This meant it could then be re-sorted on the client:

var items = [];
for (var i in $scope.model.value) { 
    value: $scope.model.value[i].value,
    sortOrder: $scope.model.value[i].sortOrder,
    id: i
items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });