Announcement

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

    Data set with setEditValue ignored in getRecords() after saveAllEdits()

    I encountered this while trying to store a Record in a field in a list grid. I could see the field with getEditedRecord() after inserting it with setEditValue(), but I didn't see it when I called getRecords() after saving.

    In this test case, I try a change to a defined field (where the field exists in the datasource) and an undefined field, and neither change appears to be showing up in getRecords(), although the list grid does show changes to the defined field.

    I tried it with 2.4, 2.0 snapshot, and the nightly from smartclient.com/builds.

    Code:
    VLayout layout = new VLayout();
    
    final ListGrid grid = new ListGrid();
    DataSource gridDS = new DataSource();
    gridDS.setClientOnly(true);
    DataSourceTextField id = new DataSourceTextField("id", "id");
    id.setPrimaryKey(true);
    id.setCanEdit(false);
    id.setHidden(false);
    DataSourceTextField a = new DataSourceTextField("a", "a");
    a.setCanEdit(true);
    a.setHidden(false);
    gridDS.setFields(id, a);
    DataClass testData[] = new DataClass[5];
    for (int currentTestItem = 0; currentTestItem < 5; currentTestItem++) {
    	testData[currentTestItem] = new DataClass();
    	testData[currentTestItem].setAttribute("id", new Integer(currentTestItem).toString());
    	testData[currentTestItem].setAttribute("a", "a");
    	testData[currentTestItem].setAttribute("b", "b");
    }
    gridDS.setTestData(testData);
    grid.setDataSource(gridDS);
    grid.setAutoFetchData(true);
    layout.addMember(grid);
    
    IButton button = new IButton("test");
    button.addClickHandler(new ClickHandler() {
    	public void onClick(ClickEvent event) {
    		grid.setEditValue(1, "a", "A");
    		grid.setEditValue(1, "b", "B");
    		grid.saveAllEdits();
    		for (Record record : grid.getRecords())
    			GWT.log("Record " + record.getAttribute("id") + " attributes: " + SC.echoAll(record.getJsObj()));
    	}
    });
    layout.addMember(button);
    
    layout.draw();
    The log shows
    Code:
    00:16:05.362  [INFO] Record 0 attributes: {id: "0", a: "a", b: "b"}
    00:16:05.364  [INFO] Record 1 attributes: {id: "1", a: "a", b: "b"}
    00:16:05.364  [INFO] Record 2 attributes: {id: "2", a: "a", b: "b"}
    00:16:05.364  [INFO] Record 3 attributes: {id: "3", a: "a", b: "b"}
    00:16:05.365  [INFO] Record 4 attributes: {id: "4", a: "a", b: "b"}
    when I click the button.

    As far as I can tell, this is equivalent to what is discussed at http://forums.smartclient.com/showthread.php?t=1761 , so I assume this should work.

    #2
    saveAllEdits() is asynchronous so you need to wait for the save to complete before getRecords() is going to contain the new data.

    Note that this is true even with a clientOnly DataSource since one of the goals of a clientOnly DataSource is to be plug-replaceable with a DataSource that does real persistence with a remote (hence, asynchronous) server.

    Comment


      #3
      Sorry, I meant to do grid.setSaveLocally(true) as well. When I do that, the changes to "a" show up both in the immediate getRecords() and the callback one, but changes to "b" are still omitted. In my situation I am trying to store a tree of records in an undefined field and it's omitted when I do saveAllEdits().

      Here's the fixed test case and results:
      Code:
      VLayout layout = new VLayout();
      
      final ListGrid grid = new ListGrid();
      DataSource gridDS = new DataSource();
      gridDS.setClientOnly(true);
      DataSourceTextField id = new DataSourceTextField("id", "id");
      id.setPrimaryKey(true);
      id.setCanEdit(false);
      id.setHidden(false);
      DataSourceTextField a = new DataSourceTextField("a", "a");
      a.setCanEdit(true);
      a.setHidden(false);
      gridDS.setFields(id, a);
      DataClass testData[] = new DataClass[5];
      for (int currentTestItem = 0; currentTestItem < 5; currentTestItem++) {
      	testData[currentTestItem] = new DataClass();
      	testData[currentTestItem].setAttribute("id", new Integer(currentTestItem).toString());
      	testData[currentTestItem].setAttribute("a", "a");
      	testData[currentTestItem].setAttribute("b", "b");
      }
      gridDS.setTestData(testData);
      grid.setDataSource(gridDS);
      grid.setAutoFetchData(true);
      grid.setSaveLocally(true);
      layout.addMember(grid);
      
      IButton button = new IButton("test");
      button.addClickHandler(new ClickHandler() {
      	public void onClick(ClickEvent event) {
      		grid.setEditValue(1, "a", "A");
      		grid.setEditValue(1, "b", "B");
      		grid.saveAllEdits(new Function() {
      			public void execute() {
      				GWT.log("In function");
      				for (Record record : grid.getRecords())
      					GWT.log("Function: Record " + record.getAttribute("id") + " attributes: " + SC.echoAll(record.getJsObj()));
      			}
      		});
      		for (Record record : grid.getRecords())
      			GWT.log("Record " + record.getAttribute("id") + " attributes: " + SC.echoAll(record.getJsObj()));
      	}
      });
      layout.addMember(button);
      
      layout.draw();
      Code:
      00:06:07.634  [INFO] In function
      00:06:07.640  [INFO] Function: Record 0 attributes: {id: "0", a: "a", b: "b"}
      00:06:07.641  [INFO] Function: Record 1 attributes: {id: "1", a: "A", b: "b"}
      00:06:07.641  [INFO] Function: Record 2 attributes: {id: "2", a: "a", b: "b"}
      00:06:07.642  [INFO] Function: Record 3 attributes: {id: "3", a: "a", b: "b"}
      00:06:07.642  [INFO] Function: Record 4 attributes: {id: "4", a: "a", b: "b"}
      00:06:07.647  [INFO] Record 0 attributes: {id: "0", a: "a", b: "b"}
      00:06:07.648  [INFO] Record 1 attributes: {id: "1", a: "A", b: "b"}
      00:06:07.648  [INFO] Record 2 attributes: {id: "2", a: "a", b: "b"}
      00:06:07.648  [INFO] Record 3 attributes: {id: "3", a: "a", b: "b"}
      00:06:07.649  [INFO] Record 4 attributes: {id: "4", a: "a", b: "b"}

      Comment


        #4
        The DataSource does not have a field "b". It's a little unclear what the ideal handling of this extra field is in this case - certainly without saveLocally it would be discarded, and it's reasonable to expect that the same thing happens when saveLocally is specified. We'd recommend just adding a "b" field.

        Comment


          #5
          Thanks for the replies, and for helping me narrow this down. I guess the most specific problem I have is that the data isn't set after saveAllEdits() when the field value was null in the original data. It does get set if the value isn't null in the original data, however. In the test below, 1 remains null but 3 is updated.

          I suppose I could somehow make sure the value is never null... if this is too obscure a use case I'll look into that.

          Here's another revised test case:
          Code:
          VLayout layout = new VLayout();
          
          final ListGrid grid = new ListGrid();
          DataSource gridDS = new DataSource();
          gridDS.setClientOnly(true);
          DataSourceTextField id = new DataSourceTextField("id", "id");
          id.setPrimaryKey(true);
          id.setCanEdit(false);
          id.setHidden(false);
          DataSourceField field = new DataSourceField("field", FieldType.ANY, "field");
          field.setCanEdit(true);
          field.setHidden(true);
          gridDS.setFields(id, field);
          DataClass testData[] = new DataClass[5];
          for (int currentTestItem = 0; currentTestItem < 5; currentTestItem++) {
          	testData[currentTestItem] = new DataClass();
          	testData[currentTestItem].setAttribute("id", new Integer(currentTestItem).toString());
          }
          Record testFieldData = new Record();
          testFieldData.setAttribute("test", "true");
          testData[3].setAttribute("field", testFieldData);
          gridDS.setTestData(testData);
          grid.setDataSource(gridDS);
          grid.setAutoFetchData(true);
          grid.setSaveLocally(true);
          layout.addMember(grid);
          
          IButton button = new IButton("test");
          button.addClickHandler(new ClickHandler() {
          	public void onClick(ClickEvent event) {
          		Record fieldData1 = new Record();
          		fieldData1.setAttribute("test", "false");
          		grid.setEditValue(1, "field", fieldData1);
          		Record fieldData3 = new Record();
          		fieldData3.setAttribute("test", "false");
          		grid.setEditValue(3, "field", fieldData3);
          		
          		grid.saveAllEdits();
          		for (Record record : grid.getRecords())
          			GWT.log("Record " + record.getAttribute("id") + 
          					" field attribute: " + SC.echoAll(record.getAttributeAsJavaScriptObject("field")));
          	}
          });
          layout.addMember(button);
          
          layout.draw();
          And the log:
          Code:
          00:14:01.735  [INFO] Record 0 field attribute: null
          00:14:01.736  [INFO] Record 1 field attribute: null
          00:14:01.736  [INFO] Record 2 field attribute: null
          00:14:01.737  [INFO] Record 3 field attribute: {__ref: {GWT Java Obj}, test: "true"}
          00:14:01.737  [INFO] Record 4 field attribute: null

          Comment


            #6
            Does this behavior occur when you've just got atomic field values (eg an Integer)? Because typically if you've got sub-records, you would use nested DataSources to describe the structure (DataSourceField.setDataSourceType()).

            Comment


              #7
              I'll look into nested data sources, I must have missed them in my searching.

              It looks like the updating/inserting works as long as the field is not hidden. If a field value is missing on a hidden field, it won't be there after saveAllEdits() for both primitive and Record fields. The edits do show up on the Record field if the record field is not hidden.

              Edit: They also don't show up if the field is setDetail(true).

              Test code... fieldA and fieldC are hidden, fieldB and fieldD are not.
              Code:
              VLayout layout = new VLayout();
              
              final ListGrid grid = new ListGrid();
              DataSource gridDS = new DataSource();
              gridDS.setClientOnly(true);
              DataSourceTextField id = new DataSourceTextField("id", "id");
              id.setPrimaryKey(true);
              id.setCanEdit(false);
              id.setHidden(false);
              DataSourceIntegerField fieldA = new DataSourceIntegerField("fieldA", "fieldA");
              fieldA.setHidden(true);
              DataSourceIntegerField fieldB = new DataSourceIntegerField("fieldB", "fieldB");
              fieldB.setHidden(false);
              DataSourceField fieldC = new DataSourceField("fieldC", FieldType.ANY, "fieldC");
              fieldC.setHidden(true);
              DataSourceField fieldD = new DataSourceField("fieldD", FieldType.ANY, "fieldD");
              fieldD.setHidden(false);
              gridDS.setFields(id, fieldA, fieldB, fieldC, fieldD);
              DataClass testData[] = new DataClass[5];
              for (int currentTestItem = 0; currentTestItem < 5; currentTestItem++) {
              	testData[currentTestItem] = new DataClass();
              	testData[currentTestItem].setAttribute("id", new Integer(currentTestItem).toString());
              }
              testData[3].setAttribute("fieldA", 14);
              testData[3].setAttribute("fieldB", 14);
              Record testFieldCData = new Record();
              testFieldCData.setAttribute("test", "true");
              testData[3].setAttribute("fieldC", testFieldCData);
              Record testFieldDData = new Record();
              testFieldDData.setAttribute("test", "true");
              testData[3].setAttribute("fieldD", testFieldDData);
              gridDS.setTestData(testData);
              grid.setDataSource(gridDS);
              grid.setAutoFetchData(true);
              grid.setSaveLocally(true);
              layout.addMember(grid);
              
              IButton button = new IButton("test");
              button.addClickHandler(new ClickHandler() {
              	public void onClick(ClickEvent event) {
              		grid.setEditValue(1, "fieldA", 28);
              		grid.setEditValue(1, "fieldB", 28);
              		Record testFieldCData1 = new Record();
              		testFieldCData1.setAttribute("test", "false");
              		grid.setEditValue(1, "fieldC", testFieldCData1);
              		Record testFieldDData1 = new Record();
              		testFieldDData1.setAttribute("test", "false");
              		grid.setEditValue(1, "fieldD", testFieldDData1);
              		
              		grid.setEditValue(3, "fieldA", 28);
              		grid.setEditValue(3, "fieldB", 28);
              		Record testFieldCData2 = new Record();
              		testFieldCData2.setAttribute("test", "false");
              		grid.setEditValue(3, "fieldC", testFieldCData2);
              		Record testFieldDData2 = new Record();
              		testFieldDData2.setAttribute("test", "false");
              		grid.setEditValue(3, "fieldD", testFieldDData2);
              		
              		grid.saveAllEdits();
              		for (Record record : grid.getRecords())
              			GWT.log("Record " + record.getAttribute("id") + ": " + SC.echoAll(record.getJsObj()) + 
              					", fieldC: " + SC.echoAll(record.getAttributeAsJavaScriptObject("fieldC")) + 
              					", fieldD: " + SC.echoAll(record.getAttributeAsJavaScriptObject("fieldD")));
              	}
              });
              layout.addMember(button);
              
              layout.draw();
              Code:
              00:25:37.994  [INFO] Record 0: {id: "0"}, fieldC: null, fieldD: null
              00:25:37.995  [INFO] Record 1: {id: "1", fieldB: 28, fieldD: Obj}, fieldC: null, fieldD: {__ref: {GWT Java Obj}, test: "false"}
              00:25:37.996  [INFO] Record 2: {id: "2"}, fieldC: null, fieldD: null
              00:25:37.997  [INFO] Record 3: {id: "3", fieldA: 14, fieldB: 28, fieldC: Obj, fieldD: Obj}, fieldC: {__ref: {GWT Java Obj}, test: "true"}, fieldD: {__ref: {GWT Java Obj}, test: "false"}
              00:25:37.998  [INFO] Record 4: {id: "4"}, fieldC: null, fieldD: null
              Last edited by abaxter; 12 Apr 2011, 11:31.

              Comment


                #8
                OK, that's looking like a real bug, but as you guessed, this is a bit obscure, meaning it won't receive very high priority, so we'd recommend pursuing your workaround of making sure there are initial values for now.

                Comment


                  #9
                  Well, I have been struggling with this bug for a bit, so it's not that obscure, I was happy to see it reported, and I hope you can publish a fix soon. The hide/show state of a ListGridField should have nothing to do with what saveAllEdits does.

                  My workaround is to create a array of Records using getEditedRecord() and use that for the further processing that I need to do with that data.

                  Comment


                    #10
                    We believe this issue is now fixed. Please try the next nightly build and let us know if you continue to see it

                    Thanks
                    Isomorphic Software

                    Comment

                    Working...
                    X