Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    SelectItem.setValueMap () does not respect LinkedHashMap order for number strings

    What steps will reproduce the problem?
    1. Create a SelectItem
    2. Setup a LinkedHashMap where the keys as "3", "2", and "1"
    3. Invoke selectItem.setValueMap (valueMap);

    What is the expected output? What do you see instead?
    I expect the order of the SelectItem values to be "3", then "2", then "1".
    Instead, I get values in order "1", then "2", then "3".
    It seems that SelectItem sorts the contents ignoring the LinkedHashMap order.
    When I setup the same SelecItem with values "c", then "b", then "a", the order is respected.
    So this could be a problem only when the keys are "numbers"...

    What version of the product are you using? On what operating system?
    SmartGWT 2.4
    GWT 2.1.1
    Windows 7

    What browser(s) does this happen in? Are there any browsers where the
    issue does not occur?
    Happens in IE 9
    Do not know if this works fine in other browsers...

    Please provide any additional information below.
    Code:
    import java.util.LinkedHashMap;
    
    import com.google.gwt.core.client.EntryPoint;
    
    import com.smartgwt.client.widgets.form.fields.SelectItem;
    import com.smartgwt.client.widgets.form.DynamicForm;
    import com.smartgwt.client.widgets.layout.HLayout;
    
    public class TestSelectItemOrdering implements EntryPoint {
    
      public void onModuleLoad () {
        
        // add a SelectItem with data sorted in order c/b/a
        // this SelectItem properly respects the LinkedHashMap order c, b, a
        final SelectItem selectItem1 = new SelectItem ();
        selectItem1.setTitle ("SelectItem with alpha keys c/b/a");
        {
          final LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String> ();
          valueMap.put ("c", "Option C");
          valueMap.put ("b", "Option B");
          valueMap.put ("a", "Option A");
          selectItem1.setValueMap (valueMap);
          selectItem1.setValue ("b");
        }
        
        // add a SelectItem with data sorted in order 3/2/1
        // this SelectItem inproperly renders the LinkedHashMap order as 1, 2, 3
        final SelectItem selectItem2 = new SelectItem ();
        selectItem2.setTitle ("SelectItem with int keys 3/2/1");
        {
          final LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String> ();
          valueMap.put ("3", "Option 3");
          valueMap.put ("2", "Option 2");
          valueMap.put ("1", "Option 1");
          selectItem2.setValueMap (valueMap);
          selectItem2.setValue ("2");
        }
    
        // add to a form
        final DynamicForm form = new DynamicForm ();
        form.setWrapItemTitles (false);
        form.setFields (selectItem1, selectItem2);
    
        // display
        final HLayout mainLayout = new HLayout ();
        mainLayout.setWidth100 ();
        mainLayout.setHeight100 ();
        mainLayout.addMember (form);
        mainLayout.draw ();
      }
    }

    #2
    Since this arbitrary sorting is in 3.0 not solved, I created a workaround today:

    Code:
    			SelectItem cbItem = new SelectItem(param.getParamName());  
    			cbItem.setTitle(param.getLabel());
    			DataSource ds= new DataSource();
    			ds.setID("ds" + new Date().getTime());
    			
    			DataSourceIntegerField pkField = new DataSourceIntegerField("id");   
    			pkField.setPrimaryKey(true);  
    			DataSourceTextField labelField= new DataSourceTextField("title");
    			ds.setFields(pkField, labelField);
    			ds.setClientOnly(true);
    			cbItem.setOptionDataSource(ds);
    			cbItem.setValueField("id");
    			cbItem.setDisplayField("title");
    			if(!AdminApp.empty(param.getValue())) {
    				cbItem.setValue(param.getValue());
    			}
    			
    			for (String key : param.getOptions().keySet()) { //where param.getOptions() is the LinkedHashMap with "numeric" ids and titles...
    				Record record= new Record();
    				record.setAttribute("id", key);
    				record.setAttribute("title", param.getOptions().get(key));
    				ds.addData(record);
    			}
    			result= cbItem;
    Attached Files

    Comment


      #3
      Encountering the same thing in 4.1p 2013-05-07

      Encountering the same thing in 4.1p 2013-05-07

      The LinkedHashMap order is preserved in my sysout but as soon as I set it as the value map it gets reordered behind the scenes, to the "natural" string order.

      Here's an example. I hard coded the map for this example but normally I'd be pulling it from the record which is why it's in the editor value map function.

      Code:
      selectedColName.setEditorValueMapFunction(new EditorValueMapFunction() 
      {
            @Override
            public LinkedHashMap<String, String> getEditorValueMap(Map values, ListGridField field, ListGrid grid)
            {
                LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();
              
                map.put("- none -", "- none -");
                map.put("1", "1");
                map.put("2", "2");
              
                System.out.println(map);  //displays in the correct order:  - none -, 1, 2
              
                return map;
            }
      });
      The picklist displays in this order: 1, 2, - none -

      How can I ensure the none value always shows first?

      Thanks!
      -B

      Comment


        #4
        This is because JavaScript Objects have a very surprising property of being order preserving for all keys except those that happen to be parsable as integers.

        The workaround is to either use optionDataSource instead, or avoid numeric keys that need to appear in non-numeric order.

        See this thread for more background.

        Comment


          #5
          Yuck! Thanks for that info - I have no control over the keys so optionDataSource it is. :)
          -B

          Comment


            #6
            The way I do this lately is this:

            When loading the SelectItem with a key value, do not use this:
            Code:
            final LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String> ();
                  valueMap.put ("c", "Option C");
                  valueMap.put ("b", "Option B");
                  valueMap.put ("a", "Option A");
            Use this instead, where you prefix each key with a 0-padded string and a dash so that you can "force" the order (this works with the latest of most major browsers/platforms):
            Code:
            final LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String> ();
                  valueMap.put ("001-c", "Option C");
                  valueMap.put ("002-b", "Option B");
                  valueMap.put ("003-a", "Option A");
            Then override getValueAsString () so that you can extract the right value:
            Code:
            @Override
            public String getValueAsString () {
                  final String value = super.getValueAsString ();
                  final int dashIndex = value.indexOf ('-');
                  return value.substring (dashIndex + 1);
            }
            FYI, I did not compile the above code...

            Comment


              #7
              Thanks for posting! Unfortunately I have no control over what the key value pairs are - they're pulled in from an external feed - but someone out there in web-land will benefit from your workaround. :)

              Comment

              Working...
              X