2

I have these two JSON maps:

{
  "1000006": "Alternate Business Phone",
  "1000008": "Alternate Home Phone",
  "1000001": "Business Phone",
  "1000003": "Clinic Phone",
  "3": "Facsimile",
  "1000007": "Home Phone",
  "1000004": "Lab Phone",
  "4": "Pager",
  "1000002": "Secure Msg Phone"
}

and

{
  "6": "Business Email",
  "1000005": "Deliver To Email",
  "7": "Personal Email"
}

Which are key-value maps alphabetized by value. I am using these two to change the contents of a drop-down menu based on another drop-down's selected item. Pics to illustrate:


Phone selected:

enter image description here


Email selected:

enter image description here


But, as you can see in the image, the order of the list items is not being preserved.

My Javascript handling the list items is this:

  var options_1 = {"1000006":"Alternate Business Phone","1000008":"Alternate Home Phone","1000001":"Business Phone","1000003":"Clinic Phone","3":"Facsimile","1000007":"Home Phone","1000004":"Lab Phone","4":"Pager","1000002":"Secure Msg Phone"};
  var options_2 = {"6":"Business Email","1000005":"Deliver To Email","7":"Personal Email"};
  function changePhoneEmailItems()
  {
    var selectedItem = document.getElementById("addNewCategory").value;
    var options;
    if('1' === selectedItem) {
        options = options_1;
    } else {
        options = options_2;
    }
    var list = document.getElementById("addNewUsageType");
    list.options.length=0;
    for(var i in options) {
        list.add(new Option(options[i], i));
    }
  }

According to this StackOverflow answer, I need to change the data structure I'm using because JSON is, by definition, unordered.

I tried changing the JSON to a new Map:

var options_1 = {"1000006":"Alternate Business Phone","1000008":"Alternate Home Phone","1000001":"Business Phone","1000003":"Clinic Phone","3":"Facsimile","1000007":"Home Phone","1000004":"Lab Phone","4":"Pager","1000002":"Secure Msg Phone"};
var options_2 = {"6":"Business Email","1000005":"Deliver To Email","7":"Personal Email"};
var options_1_map = new Map(options_1);
console.log(options_1_map);

But it threw an error:

TypeError: options_1 is not iterable

How do I change the JSON object to preserve the original order?

NOTE: My JSON is coming from a Spring controller which is "wrapping" the map in JSON to send to the view. But I am able to modify the controller if there is a more sensible way to transfer the map from the controller to the view.

EDIT: For good measure, the controller code that is generating the JSON is:

for(int i = 1; i <= 2; i++) {
    JsonObject json = new JsonObject();
    HashMap<String, String> CDCONTMETHTP = (HashMap<String, String>)model.get("CDCONTMETHTP_" + i);
    for(Entry<String, String> option : CDCONTMETHTP.entrySet()) {
        json.addProperty(option.getKey(), option.getValue());
    }
    model.put("options_" + i, json);
}

Which I am able to modify if need be.

ryvantage
  • 13,064
  • 15
  • 63
  • 112
  • 1
    `options_1` is not in the correct form to be provided as an argument to the constructor of Map. It needs to be an Array of Arrays. The inner Arrays need to be of length 2 where the first element of the inner Array is the key and the second should be the value. See [MDN Map parameters docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Parameters) – zero298 Jan 25 '19 at 15:15
  • It's because you are tyring to iterate over an object instead of an array! – Silvio Biasiol Jan 25 '19 at 15:15
  • @zero298 could you re-format the JSON to show me the appropriate format and leave that as an answer? Again, I can control the way the JSON comes off the controller but I'm not sure how to modify it – ryvantage Jan 25 '19 at 15:16

3 Answers3

6

Your JSON maps are key-value pairs and there is no way to preserve the ordering of keys. You can convert your JSON maps to Arrays, which will preserve the order.

Instead of this JSON:

{
  "6": "Business Email",
  "1000005": "Deliver To Email",
  "7": "Personal Email"
}

Send this JSON:

[
  {"id": 6, "text": "Business Email"},
  {"id": 1000005, "text": "Deliver To Email"},
  {"id": 7, "text": "Personal Email"}
]
David
  • 3,552
  • 1
  • 13
  • 24
  • Your answer worked, but I had to modify the for loop. I posted the solution as answer below. – ryvantage Jan 25 '19 at 15:47
  • JSON serializes and deserializes keys in insertion time order so you can very much affect the ordering if you use a library that handles this. That said it’s probably better to use a list to specify order, stable stringification is more for using objects as complex hash keys – millimoose Jan 25 '19 at 15:50
0

Like someone said here; just put _ before the numbers.

o/ Have a good day

jusdepatate
  • 38
  • 1
  • 7
  • The problem with this is that these are database keys that are passed back to the controller so I'd have to, later, remove those `_`. – ryvantage Jan 25 '19 at 15:27
0

David's answer worked, but not without modifying the for loop that iterated through the elements. I have posted the full solution here:

var options_1 = {"1000006":"Alternate Business Phone","1000008":"Alternate Home Phone","1000001":"Business Phone","1000003":"Clinic Phone","3":"Facsimile","1000007":"Home Phone","1000004":"Lab Phone","4":"Pager","1000002":"Secure Msg Phone"};
var options_2 = {"6":"Business Email","1000005":"Deliver To Email","7":"Personal Email"};
function changePhoneEmailItems()
{
    var selectedItem = document.getElementById("addNewCategory").value;
    var options;
    if('1' === selectedItem) {
        options = options_1;
    } else {
        options = options_2;
    }

    var list = document.getElementById("addNewUsageType");
    list.options.length=0;
    Object.keys(options).forEach(function(i) {
        list.add(new Option(options[i].value, options[i].key))          
    });
}
ryvantage
  • 13,064
  • 15
  • 63
  • 112