Announcement

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

    ListGrid grouping value map bug

    There's a bug in the optionDataSource/valueMap lookup when using grouping and optionDataSources

    If you group by a column that can take multiple values, it correctly substitutes the valueMap key -> string for single values, but for double values the key values are shown with a "," in between.

    It looks to me like the lookup is being done at the wrong time, ie, it combines the keys into a comma list THEN does the lookup (and can't find it). It should do the lookup for the key, THEN combine in a comma list.

    #2
    What version are you seeing this in, hosted mode or not, and how do you reproduce it?

    Comment


      #3
      Sorry for the lame bug report. SC_SNAPSHOT-2011-06-30/Pro Deployment 2011-06-30 and observed in Production (ie, non-hosted) mode.

      I'll work on a test case, just did not have the time to do that.

      The group by field has multiple=true, type=sequence, and an optionDataSource which maps the Long id to a String label. For any records with more than one Long value, it shows the Long values instead of the String label. When only a single Long value is set (for the record), it works correctly.

      Comment


        #4
        We've got test cases like this. You could create this problem if the value for the field were delivered as a String instead of a two-element array. Check the RPC tab for what your server is delivering, and check the live value programmatically to verify it's still an Array.

        Comment


          #5
          this one has still got me. a worse problem than the grouping bug is when i filter on a field using the filter editor, it does not show records which contain the filtered value (if those records have more than 1 value). single valued records filter as expected.

          i tried inspecting via the resultset to see what was in there and confirmed the value was an array of integers (rather than strings).

          i am using local filterting.

          Comment


            #6
            if i remove the optionDataSource definition from the field then it filters as expected (eg, filter on 520 and a record with 520,525 shows up - before only records with 520 would show up)

            Comment


              #7
              i put a cellFormatter on the ListGridField.

              Code:
              listGridField.setCellFormatter(new CellFormatter() {
              							@Override
              							public String format(Object value,
              									ListGridRecord record, int rowNum,
              									int colNum) {
              the value passed in is a JavaScriptObject$ - when I call

              Code:
              JSOHelper.convertToJava((JavaScriptObject) value);
              it returns an ArrayList with a pair of strings in it.

              this looks to me like the optionDataSource mapping has already been applied at this point - maybe that is correct.

              my current workaround for this issue is to not use optionDataSource - this is pretty dire. :/ is there anything else i can check to ensure i have not screwed up the definition.

              Comment


                #8
                As always - a test case that clearly demonstrates a bug is the right thing to produce.

                Comment


                  #9
                  Yeah, I'll try again. My standalone testcase using an optionDataSource on the client side seemed to work ok.

                  If I can't that working I'll try making a testcase using one of the server examples.

                  Comment


                    #10
                    ok, I modified the builtinDS example.

                    add a few records and then try filtering on the the "items" field when a record has more than one item in it.

                    expected: records which contain the filtered value will be shown
                    observed: records that contain *only* the (one) filtered value (ie, do not have more than one value) are shown. records with multiple values are always hidden.


                    Code:
                    package com.smartgwt.sample.client;
                    
                    import com.google.gwt.core.client.EntryPoint;
                    import com.smartgwt.client.core.KeyIdentifier;
                    import com.smartgwt.client.data.DataSource;
                    import com.smartgwt.client.data.DataSourceField;
                    import com.smartgwt.client.data.Record;
                    import com.smartgwt.client.data.ResultSet;
                    import com.smartgwt.client.types.CriteriaPolicy;
                    import com.smartgwt.client.types.FetchMode;
                    import com.smartgwt.client.types.FieldType;
                    import com.smartgwt.client.types.SelectionStyle;
                    import com.smartgwt.client.types.SortArrow;
                    import com.smartgwt.client.util.KeyCallback;
                    import com.smartgwt.client.util.Page;
                    import com.smartgwt.client.util.SC;
                    import com.smartgwt.client.widgets.IButton;
                    import com.smartgwt.client.widgets.Label;
                    import com.smartgwt.client.widgets.events.ClickEvent;
                    import com.smartgwt.client.widgets.events.ClickHandler;
                    import com.smartgwt.client.widgets.form.DynamicForm;
                    import com.smartgwt.client.widgets.grid.ListGrid;
                    import com.smartgwt.client.widgets.grid.ListGridField;
                    import com.smartgwt.client.widgets.grid.ListGridRecord;
                    import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
                    import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
                    import com.smartgwt.client.widgets.layout.HLayout;
                    import com.smartgwt.client.widgets.layout.VStack;
                    import com.smartgwt.client.widgets.viewer.DetailViewer;
                    
                    /**
                     * Entry point classes define <code>onModuleLoad()</code>.
                     */
                    public class BuiltInDS implements EntryPoint {
                    	private ListGrid boundList;
                    	private DynamicForm boundForm;
                    	private IButton saveBtn;
                    	private DetailViewer boundViewer;
                    	private IButton newBtn;
                    
                    	/**
                    	 * This is the entry point method.
                    	 */
                    	public void onModuleLoad() {
                    		KeyIdentifier debugKey = new KeyIdentifier();
                    		debugKey.setCtrlKey(true);
                    		debugKey.setKeyName("D");
                    
                    		Page.registerKey(debugKey, new KeyCallback() {
                    			public void execute(String keyName) {
                    				SC.showConsole();
                    			}
                    		});
                    
                    		VStack vStack = new VStack();
                    		vStack.setLeft(175);
                    		vStack.setTop(75);
                    		vStack.setWidth("70%");
                    		vStack.setMembersMargin(20);
                    
                    		Label label = new Label();
                    		label.setContents("<ul>"
                    				+ "<li>select a datasource from the list at left to bind to these components</li>"
                    				+ "<li>click a record in the grid to view and edit that record in the form</li>"
                    				+ "<li>click <b>New</b> to start editing a new record in the form</li>"
                    				+ "<li>click <b>Save</b> to save changes to a new or edited record in the form</li>"
                    				+ "<li>click <b>Clear</b> to clear all fields in the form</li>"
                    				+ "<li>click <b>Filter</b> to filter (substring match) the grid based on form values</li>"
                    				+ "<li>click <b>Fetch</b> to fetch records (exact match) for the grid based on form values</li>"
                    				+ "<li>double-click a record in the grid to edit inline (press Return, or arrow/tab to another record, to save)</li>"
                    				+ "</ul>");
                    		vStack.addMember(label);
                    
                    [b]		DataSource dataSource = new DataSource();
                    		dataSource.setID("testing");
                    		DataSourceField keyField = new DataSourceField("key",
                    				FieldType.SEQUENCE);
                    		keyField.setPrimaryKey(true);
                    		DataSourceField items = new DataSourceField("items", FieldType.SEQUENCE);
                    		items.setMultiple(true);
                    		items.setAttribute("optionDataSource", "supplyItem");
                    		items.setAttribute("valueField", "itemID");
                    		items.setAttribute("displayField", "itemName");
                    
                    		dataSource.addField(keyField);
                    		dataSource.addField(items);
                    		dataSource.setClientOnly(true);
                    [/b]
                    		boundList = new ListGrid();
                    		boundList.setHeight(200);
                    		boundList.setCanEdit(true);
                    		boundList.setShowFilterEditor(true);
                    		boundList.addRecordClickHandler(new RecordClickHandler() {
                    			public void onRecordClick(RecordClickEvent event) {
                    				Record record = event.getRecord();
                    				boundForm.editRecord(record);
                    				saveBtn.enable();
                    				boundViewer.viewSelectedData(boundList);
                    			}
                    		});
                    		vStack.addMember(boundList);
                    
                    		boundForm = new DynamicForm();
                    		boundForm.setNumCols(6);
                    		boundForm.setAutoFocus(false);
                    		vStack.addMember(boundForm);
                    
                    		HLayout hLayout = new HLayout(10);
                    		hLayout.setMembersMargin(10);
                    		hLayout.setHeight(22);
                    
                    		saveBtn = new IButton("Save");
                    		saveBtn.addClickHandler(new ClickHandler() {
                    			public void onClick(ClickEvent event) {
                    				boundForm.saveData();
                    				if (!boundForm.hasErrors()) {
                    					boundForm.clearValues();
                    					saveBtn.disable();
                    				}
                    			}
                    		});
                    		hLayout.addMember(saveBtn);
                    
                    		newBtn = new IButton("New");
                    		newBtn.addClickHandler(new ClickHandler() {
                    			public void onClick(ClickEvent event) {
                    				boundForm.editNewRecord();
                    				saveBtn.enable();
                    			}
                    		});
                    		hLayout.addMember(newBtn);
                    
                    		IButton clearBtn = new IButton("Clear");
                    		clearBtn.addClickHandler(new ClickHandler() {
                    			public void onClick(ClickEvent event) {
                    				boundForm.clearValues();
                    				saveBtn.disable();
                    			}
                    		});
                    		hLayout.addMember(clearBtn);
                    
                    		IButton filterBtn = new IButton("Filter");
                    		filterBtn.addClickHandler(new ClickHandler() {
                    			public void onClick(ClickEvent event) {
                    				boundList.filterData(boundForm.getValuesAsCriteria());
                    				saveBtn.disable();
                    			}
                    		});
                    		hLayout.addMember(filterBtn);
                    
                    		IButton fetchBtn = new IButton("Fetch");
                    		fetchBtn.addClickHandler(new ClickHandler() {
                    			public void onClick(ClickEvent event) {
                    				boundList.fetchData(boundForm.getValuesAsCriteria());
                    				saveBtn.disable();
                    			}
                    		});
                    		hLayout.addMember(fetchBtn);
                    
                    		vStack.addMember(hLayout);
                    
                    		boundViewer = new DetailViewer();
                    		vStack.addMember(boundViewer);
                    
                    		vStack.draw();
                    		
                    		bindComponents(dataSource);
                    	}
                    
                    	private void bindComponents(DataSource dataSource) {
                    		DataSource ds = dataSource;
                    		boundList.setDataSource(ds);
                    		boundViewer.setDataSource(ds);
                    		boundForm.setDataSource(ds);
                    		boundList.fetchData();
                    		newBtn.enable();
                    		saveBtn.disable();
                    	}
                    }
                    Last edited by atomatom; 13 Jul 2011, 21:09.

                    Comment


                      #11
                      My workaround to this right now is to replace these fields with the displayField value of the optionDataSource. On the server, I populate these fields by doing the lookup (value -> display).

                      Comment


                        #12
                        That's not a workaround, that's the preferred strategy that docs tell you to use (specifically ListGridField.optionDataSource).

                        As far as the test case, your assumption appears to be that the default client-side filtering behavior for a multiple field is to consider a value to be a match if it matches any member of the array?

                        Comment


                          #13
                          That's not a workaround, that's the preferred strategy that docs tell you to use (specifically ListGridField.optionDataSource).
                          I think you must misunderstand what I am doing. On the server, I am doing the mapping from String -> Long instead of using the optionDataSource valueField and displayField. The use of displayField causes problems on the client side when there is a combination of multiple=true and either grouping or filtering.

                          As far as the test case, your assumption appears to be that the default client-side filtering behavior for a multiple field is to consider a value to be a match if it matches any member of the array?
                          Yes, that was my assumption. One that is consistent with the behavior seen when multiple=true and not using displayField.

                          If this is not a bug (which it still seems like to me), I'd like to understand the criteria behaviour. I didn't find any clear description int the javadoc. Did I miss it?

                          Comment


                            #14
                            I got the desired behavior in my application by switching to listGrid.filterData() instead of fetchData().

                            I would like to know the answer the last question you asked me. What is the correct behavior?

                            Comment


                              #15
                              fetchData() is always an exact match. Analogous to the behavior for Strings, filterData() means the criteria value has to appear in the array. So, no bug, you just needed to switch to filterData to get the desired filtering behavior.

                              Comment

                              Working...
                              X