Announcement

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

    How can I refresh OptionDataSource in SelectItem?

    I created SelectItem with OptionDataSource. The data are fetched when the component is created, however I'm unable to refetch the data later. I am using my own custom DataSource

    I tried using the following code, when I need to refresh the contents of SelectItem (it doesn't work):

    Code:
         dataSource.invalidateCache();
         dataSource.fetchData();
         selectItem.fetchData();
    It doesn't matter whether I invoke setCacheAllData(true) or not, when I create the DataSource.

    I'm using SmartGWT 2.4.

    How can I force SelectItem to reload the data from the OptionDataSource?

    #2
    SelectItem.fetchData() is correct, remove the other calls.

    If you're having trouble, try putting together a standalone test case so that people can see all the code involved.

    Comment


      #3
      When I created a standalone test case the selectItem.fetchData() actually worked as expected and I was unable to figure out why it doesn't work in the more complex application.

      However I stumbled across another problem and I prepared a standalone test case.

      The test case consists of the SelectItem and the ListGrid. When I click on the button "Fetch" the SelectItem is filled with new data. What should I invoke in ClickHandler to refresh the ListGridField so that it would fetch new data from OptionDataSource?

      Gridtest.java:
      Code:
      package com.example.client;
      
      import com.google.gwt.core.client.EntryPoint;
      import com.smartgwt.client.widgets.Button;
      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.form.fields.SelectItem;
      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.layout.VLayout;
      
      public class Gridtest implements EntryPoint {
      
          @Override
          public void onModuleLoad() {
              VLayout vLayout = new VLayout(10);
              vLayout.setWidth100();
              vLayout.setHeight100();
              
              DynamicForm form = new DynamicForm();
              final SelectItem selectItem = new SelectItem("name","Name");
              selectItem.setOptionDataSource(new ExampleDS());
              form.setFields(selectItem);
              vLayout.addMember(form);
              
              ListGrid listGrid = new ListGrid();
              listGrid.setCanEdit(true);
              
              ListGridField nameField = new ListGridField("name","Name");
              
              nameField.setOptionDataSource(new ExampleDS());
              nameField.setAutoFetchDisplayMap(true);
              nameField.setEditorType(new SelectItem());
              listGrid.setFields(nameField);
              
              listGrid.setWidth(200);
              listGrid.setHeight(80);
              vLayout.addMember(listGrid);
              
              ListGridRecord record = new ListGridRecord();
              record.setAttribute("name", "name-0");
              listGrid.setData(new ListGridRecord[] { record });
              
              Button button = new Button("Fetch");
              button.addClickHandler(new ClickHandler() {
                  
                  @Override
                  public void onClick(ClickEvent event) {
                      selectItem.fetchData();
                  }
              });
              vLayout.addMember(button);
              
              vLayout.draw();
          }
      
      }
      ExampleDS.java:
      Code:
      package com.example.client;
      
      import com.smartgwt.client.data.DSRequest;
      import com.smartgwt.client.data.DSResponse;
      import com.smartgwt.client.data.DataSource;
      import com.smartgwt.client.data.Record;
      import com.smartgwt.client.data.fields.DataSourceTextField;
      import com.smartgwt.client.types.DSDataFormat;
      import com.smartgwt.client.types.DSProtocol;
      
      public class ExampleDS extends DataSource {
          private int counter = 1;
          
          ExampleDS() {
              setDataProtocol (DSProtocol.CLIENTCUSTOM);
              setDataFormat (DSDataFormat.CUSTOM);
              setClientOnly (false);
              addField(new DataSourceTextField("name"));
          }
          
          @Override
          protected Object transformRequest (DSRequest request) {
              counter++;
              String requestId = request.getRequestId ();
              DSResponse response = new DSResponse ();
              response.setAttribute ("clientContext", request.getAttributeAsObject ("clientContext"));
              response.setStatus (0);
              switch (request.getOperationType ()) {
                  case FETCH:
                      Record[] records = new Record[counter];
                      for(int i=0;i<counter;i++) {
                          records[i] = new Record();
                          records[i].setAttribute("name","name-"+i);
                      }
                      response.setData(records);
                      processResponse(requestId, response);
                      break;
                  default:
                      // Operation not implemented.
                      break;
              }
              return request.getData ();
          }
      }
      SmartGWT 2.4, Mozilla Firefox 3.6.16.

      Comment


        #4
        The data will be automatically updated via cache sync (see ResultSet docs) if updates/adds/removes are performed within the same application. The only way to do a full refresh is setFields() on the ListGrid.

        By the way, we noticed you propagating "clientContext" in your clientCustom DataSource. This should be automatic. Did you find some reason you needed to do this?

        Comment


          #5
          I cannot rely on cache sync, because the data changes outside of the application.

          I removed the clientContext, I don't know exactly what it meant.

          > The only way to do a full refresh is setFields() on the ListGrid.
          When I do setFields, the valueMap does not update. In the following example I have 4 records (btw why are there 4 records and not 2? Why are there 3 fetches instead of 1?):
          id-0, name-0
          id-1, name-1
          id-2, name-2
          id-3, name-3

          The valueMap only applies to name-0 and name-1 (I assume these are the records that are fetched for the first time). After selecting name-2 and clicking elsewhere id-2 is shown in ListGrid instead of name-2.

          Gridtest.java:
          Code:
          package com.example.client;
          
          import com.google.gwt.core.client.EntryPoint;
          import com.smartgwt.client.widgets.form.fields.SelectItem;
          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.layout.VLayout;
          
          public class Gridtest implements EntryPoint {
              private ListGrid listGrid;
              
              @Override
              public void onModuleLoad() {
                  VLayout vLayout = new VLayout(10);
                  vLayout.setWidth100();
                  vLayout.setHeight100();
                  
                  listGrid = new ListGrid();
                  listGrid.setCanEdit(true);
                  
                  ListGridField nameField = new ListGridField("name","Name");
                  nameField.setOptionDataSource(new ExampleDS());
                  nameField.setAutoFetchDisplayMap(true);
                  nameField.setEditorType(new SelectItem());
                  nameField.setDisplayField("name");
                  nameField.setValueField("id");
                  listGrid.setFields(nameField);
                  
                  listGrid.setWidth(200);
                  listGrid.setHeight(80);
                  vLayout.addMember(listGrid);
                  
                  ListGridRecord record = new ListGridRecord();
                  record.setAttribute("id", "id-0");
                  record.setAttribute("name", "name-0");
                  listGrid.setData(new ListGridRecord[] { record });
                  
                  vLayout.draw();
              }
          
          }
          ExampleDS.java:
          Code:
          package com.example.client;
          
          import com.smartgwt.client.data.DSRequest;
          import com.smartgwt.client.data.DSResponse;
          import com.smartgwt.client.data.DataSource;
          import com.smartgwt.client.data.Record;
          import com.smartgwt.client.data.fields.DataSourceTextField;
          import com.smartgwt.client.types.DSDataFormat;
          import com.smartgwt.client.types.DSProtocol;
          
          public class ExampleDS extends DataSource {
              private int counter = 1;
              
              ExampleDS() {
                  setDataProtocol(DSProtocol.CLIENTCUSTOM);
                  setDataFormat(DSDataFormat.CUSTOM);
                  setClientOnly(false);
                  addField(new DataSourceTextField("id"));
                  addField(new DataSourceTextField("name"));
              }
              
              @Override
              protected Object transformRequest (DSRequest request) {
                  counter++;
                  String requestId = request.getRequestId ();
                  DSResponse response = new DSResponse ();
                  response.setStatus (0);
                  switch (request.getOperationType ()) {
                      case FETCH:
                          Record[] records = new Record[counter];
                          for(int i=0;i<counter;i++) {
                              records[i] = new Record();
                              records[i].setAttribute("id","id-"+i);
                              records[i].setAttribute("name","name-"+i);
                          }
                          response.setData(records);
                          processResponse(requestId, response);
                          break;
                      default:
                          // Operation not implemented.
                          break;
                  }
                  return request.getData ();
              }
          }
          How can I refresh valueMap?

          Comment


            #6
            Did you post the wrong code sample? There's only one call to setFields() here, the initial one which causes initial loading. Then if you want to refresh the data at a later time a second call would be required.

            Comment


              #7
              I didn't post the wrong code sample. Just to be sure I copied it back from my previous post, compiled and checked the result.

              You are right that there is only one call to setFields. After I understand what I am doing wrong with this example I will call setFields more than once. I expected to see 2 records in the SelectItem inside the ListGrid. However there are 4 records.

              I debugged the code so that I can tell you the exact sequence of events:
              1. I enter the webpage with the application.
              2. In the last line of onModuleLoad method, which is vLayout.draw(), transformRequest (from class ExampleDS) is called for the first time and the counter gets incremented. counter now equals 2, so 2 records are passed to response.setData.
              3. Method onModuleLoad finishes. I can see the webpage has loaded. I can see there is "name-0" showing in the ListGrid.
              4. I double-click the "name-0" record that is showing in the ListGrid.
              5. The method transformRequest gets called twice, incrementing the counter to 4, so there are now 4 records generated and passed to response.setData.
              6. I click the arrow-down icon (it is the arrow that is part of the SelectItem in the ListGrid).
              7. The method transformRequest gets called again, counter gets incremented to 5.
              8. There are now 4 items showing in the SelectItem:
              name-0
              name-1
              name-2
              name-3.

              I can now exit the SelectItem editor by clicking outside the ListGrid and double-click the editor again to see the list with records as many times as I want. There are always 4 records. The method transformRequest is never called again.

              9. I pick "name-0" and click outside the ListGrid, so that the SelectItem editor exits and the ListGrid is showing "name-0". I do the same thing with the other 3 records and after I click outside the ListGrid, I have the following record showing in the ListGrid:

              When I pick "name-0", there is "name-0" in the ListGrid.
              When I pick "name-1", there is "name-1" in the ListGrid.
              When I pick "name-2", there is "id-2" in the ListGrid.
              When I pick "name-3", there is "id-3" in the ListGrid.

              It looks to me like the valueMap was initialized only in the initial fetch with the records: (id-0, name-0) and (id-1, name-1).

              Why are there 4 records instead of 2? What causes the lack of mapping of "id-2" and "id-3"?

              Comment


                #8
                See the docs for listGridField.optionDataSource - the entire set of available records is fetched once and used from there on. There is no change detection except cache sync. A call to setFields() is required to cause a re-fetch. The SelectItems, on the other hand, will fetch data when they are first created as editing starts, or when the pickList is first opened, depending on their autoFetchData settings.

                What you've basically done is set up a DataSource that returns different results for every single fetch - an implausibly dynamic DataSource that's going to cause staleness no matter what strategy is used - if you work through the rules above you'll see why you get the results you do. If you think any of the results are incorrect, please point out why (with reference to the rules as documented).

                If you're worried about staleness due to concurrent updates, the correct approach is to use DataSource.updateCaches() to inform all components of changes made by other users, by sending such updates along with fetch responses as additional data and calling DataSource.updateCaches() with that data.

                Comment

                Working...
                X