Announcement

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

    ValuesManager and MultiFileItem

    SmartClient Version: v10.0p_2015-08-28/Pro Deployment (built 2015-08-28)

    Hi I have a dynamic form with a MultiFileItem in it.

    It has worked fine until now, but when I tried to move the MultiFileItem to a separate form and connect the 2 forms with a ValuesManager it stopped working.

    By stopped working I mean that it doesn't upload files. It behaves like the master record is being newly created even though it is not (I call ValuesManager.fetchData()), and when I call ValuesManager.saveData() it doesn't upload the files then either.

    Do I need to do something special when using a MultiFileItem in a ValuesManager?

    MultiFileItem:
    Code:
    MultiFileItem files = new MultiFileItem("file", "File Attachments");
    files.setWidth(fieldWidth);
    files.setAttribute("dataSource", "scrum_backlog_userStoryFiles");
    files.setTitleOrientation(orientation);
    files.setIconVAlign(VerticalAlignment.TOP);
    files.setColSpan(numberOfCols / 2);
    files.setEndRow(true);
    MultiFileItem's DataSource:
    Code:
    <DataSource  
        ID="scrum_backlog_userStoryFiles"
        serverConstructor="it.forecast.server.servlets.scrum.userStories.UserStoryFilesServlet">
        <fields>
             <field name="fileId" type="sequence" primaryKey="true" hidden="true"/>
             <field name="masterRecordId" type="integer" foreignKey="scrum_backlog_userStoryDetails.id" hidden="true"/>
             <field name="file" type="binary" />
          </fields>
    </DataSource>
    ValuesManager's DataSource:
    Code:
    <DataSource  
    	ID="scrum_backlog_userStoryDetails"
    	serverConstructor="it.forecast.server.servlets.scrum.userStories.UserStoryDetailsServlet">
    	<fields>
    		<field name="id"                      type="sequence"      hidden="true"				primaryKey="true"	/>
    		<field name="title"                   type="text"          title="Title"				length="255"	required="true"	/>
    		<field name="acceptanceCriteria"      type="text"	title="Acceptance Criteria"	length="100000"		/>
    		<field name="estimate"                type="integer"       title="Estimated Points"		length="9"			>
    			<validators>
    				<validator type="integerRange" min="0" />
    			</validators>
    		</field>
    		<field name="completionDate"          type="date"          title="Completion Date"		dateFormatter="toEuropeanShortDate"	 />
    		<field name="epic"                    type="text"          title="Epic"					length="255"		/>
    	</fields>
    </DataSource>
    Let me know if you need more info from me.
    Last edited by Niels_EMP; 4 Sep 2015, 06:15. Reason: missed a word

    #2
    Can you show us a simple, runnable EntryPoint class which demonstrates the problem? This will allow us to see exactly how your form, your ValuesManager and your items are configured, and make sure we're looking in the right place.

    Thanks
    Isomorphic Software

    Comment


      #3
      Sorry it took me a while to get back to this but I have finally made a Testcase that shows the problem.

      With the useValuesManager boolean you can control whether to use a values manager or just a normal dynamic form.
      It works great when using the form, but not when using the values manager.
      Even after you press the fetch button to call vm.fetchData() the MultiFileItem still doesn't register that it has recieved a PrimaryKey from the masterDS.
      Similarly when pressing the save button and calling vm.saveData() the MultiFileItem doesn't try to save the added files to the returned PK.

      Let me know if this is sufficient or you need more info.

      EntryPoint:
      Code:
      import com.google.gwt.core.client.EntryPoint;
      import com.smartgwt.client.data.DataSource;
      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.ValuesManager;
      import com.smartgwt.client.widgets.form.fields.MultiFileItem;
      import com.smartgwt.client.widgets.layout.VLayout;
      
      
      public class TestCase implements EntryPoint {
      
          @Override
          public void onModuleLoad() {
              // Change to switch between using normal form or valuesManager
              final boolean useValuesManager = true;
              
              DataSource masterDS = DataSource.get("multiUploadMaster");
              DataSource fileDS = DataSource.get("multiUploadDetail");
              
              final ValuesManager vm = new ValuesManager();
              vm.setDataSource(masterDS);
              
              MultiFileItem files = new MultiFileItem("file", "File Attachments");
              files.setAttribute("dataSource", fileDS.getID());
              
              final DynamicForm filesForm = new DynamicForm();
              filesForm.setWidth(400);
              filesForm.setFields(files);
              
              if(useValuesManager)
              {
                  filesForm.setValuesManager(vm);
              }
              else
              {
                  filesForm.setDataSource(masterDS);
              }
              
              final VLayout mainLayout = new VLayout();
              
              Button fetchButton = new Button("Fetch PK");
              fetchButton.addClickHandler(new ClickHandler() {
                  
                  @Override
                  public void onClick(ClickEvent event) {
                      if(useValuesManager)
                      {
                          vm.fetchData(null);
                      }
                      else
                      {
                          filesForm.fetchData();
                      }
                  }
              });
              Button saveButton = new Button("Save Files");
              saveButton.addClickHandler(new ClickHandler() {
                  
                  @Override
                  public void onClick(ClickEvent event) {
                      if(useValuesManager)
                      {
                          vm.saveData();
                      }
                      else
                      {
                          filesForm.saveData();
                      }
                  }
              });
              
      
              mainLayout.addMember(fetchButton);
              mainLayout.addMember(saveButton);
              mainLayout.addMember(filesForm);
              
              mainLayout.draw();
          }
      }
      multiUploadMaster.ds.xml:
      Code:
      <DataSource 
          ID="multiUploadMaster" 
          serverConstructor="MultiUploadMasterServlet">
          <fields>
              <field name="id" type="sequence" primaryKey="true" hidden="true" />
          </fields>
      </DataSource>
      ​
      multiUploadDetail.ds.xml:
      Code:
      <DataSource 
          ID="multiUploadDetail" 
          serverConstructor="MultiUploadDetailServlet">
           <fields>
              <field name="id" type="sequence" primaryKey="true" hidden="true" />
              <field name="uploadTestId" type="integer" foreignKey="multiUploadMaster.id" hidden="true" />
              <field name="file" type="binary" />
           </fields>
      </DataSource>
      ​
      MultiUploadMasterServlet.java
      Code:
      import java.util.HashMap;
      import java.util.Map;
      
      import com.isomorphic.datasource.BasicDataSource;
      import com.isomorphic.datasource.DSRequest;
      import com.isomorphic.datasource.DSResponse;
      
      
      public class MultiUploadMasterServlet extends BasicDataSource {
          
          public DSResponse executeAdd(DSRequest req) throws Exception {  
              Map createdRecord = createRecord(req.getValues());  
              return new DSResponse(createdRecord);  
          }  
          
          public DSResponse executeUpdate(DSRequest req) throws Exception {  
              Map updatedRecord = updateRecord(req.getValues());  
              return new DSResponse(updatedRecord);  
          }  
          
          public DSResponse executeFetch(DSRequest req) throws Exception {  
              Map record = fetchRecord(req.getCriteria());  
              return new DSResponse(record);  
          }
          
          private Map createRecord (Map values) {  
              System.out.println("Saving form! returning PK");
              Map<String, Integer> m = new HashMap<>();
              m.put("id", 1);
              return m;  
          } 
        
          private Map fetchRecord (Map criteria) {  
              
              System.out.println("Fetching primary key!");
              Map<String, Integer> m = new HashMap<>();
              m.put("id", 1);
              return m;  
          }
          
          private Map updateRecord (Map values) {  
              System.out.println("Update form called!");
              return values;
          }  
      }
      ​
      MultiUploadDetailServlet.java
      Code:
      import java.util.ArrayList;
      import java.util.List;
      import java.util.Map;
      
      import com.isomorphic.datasource.BasicDataSource;
      import com.isomorphic.datasource.DSRequest;
      import com.isomorphic.datasource.DSResponse;
      
      
      public class MultiUploadDetailServlet extends BasicDataSource {
          public DSResponse executeAdd(DSRequest req) throws Exception {  
              Map createdRecord = createRecord(req.getValues());  
              return new DSResponse(createdRecord);  
          }  
        
          public DSResponse executeFetch(DSRequest req) throws Exception {  
              List records = fetchRecords(req.getCriteria());  
              return new DSResponse(records);  
          }  
        
          public DSResponse executeRemove(DSRequest req) throws Exception {  
              Map removedRecord = removeRecord(req.getValues());  
              return new DSResponse(removedRecord);  
          }  
        
          public DSResponse executeUpdate(DSRequest req) throws Exception {  
              Map updatedRecord = updateRecord(req.getValues());  
              return new DSResponse(updatedRecord);  
          }  
          
          private Map createRecord (Map values) {  
              System.out.println("Create file Called!");
              return values;  
          }  
        
          private List fetchRecords (Map criteria) {  
              
              System.out.println("Fetch files called!");
              
              return new ArrayList<>();  
          }  
        
          private Map removeRecord (Map values) {  
              System.out.println("Delete file called!");
              return values;
          }
          
          private Map updateRecord (Map values) {  
              System.out.println("Update file called!");
              return values;
          }  
      }
      ​
      Attached Files

      Comment


        #4
        Hi Niels_EMP,

        I don't know if this helps, but in an other occasion the solution was to have a HiddenItem("pk") in every DynamicForm of the ValuesManager, see this post by Isomorphic.
        This would not explain why it is different from using just a DynamicForm, but perhaps this is the explanation:

        Calling ValuesManager.setValues() on a ValuesManager will automatically route new field values to whichever member form is showing an editor for that field.
        Perhaps this means that if a separate DynamicForm loads data, it knows about all fields in the record and that if a DynamicForm is administrated by a ValuesManager, the ValuesManager will only pass the relevant data to its DynamicForms and discard the rest. This would explain your result.

        Best regards
        Blama

        Comment


          #5
          Okay so I added a HiddenItem("id") to the filesForm and that solved 1 of the problems. Now when vm.fetchData() is called the MultiFileItem correctly sends a fetch request to fetch the files and new files are saved immediately.

          But when saving a new record the MultiFileItem does not try to save any files when the newly created id is returned.
          To say it in another way, when I call valuesManager.saveDate() and the valuesManager has not previously fetched a private key, none of the files added to MultiFileItem are saved. Instead the MultiFileItem calls a fetch and all the added files are discarded.

          What am I doing wrong / missing ?

          Comment


            #6
            Hey Isomorphic I still haven't been able to solve this completely.

            I have added a HiddenItem with the pk to the files form and that solved some of it as explained above, but I am still not able to upload files when saving a new record.

            Can you take a look at my Test Case above and tell me what is missing?

            Comment


              #7
              Sure we'll take a look.

              Can you show us the code snippet you used to ad the HiddenItem? We just want to make sure we're duplicating your usage exactly so we see what you're seeing.
              Thanks

              Isomorphic Software

              Comment


                #8
                sure
                Code:
                HiddenItem pkItem = new HiddenItem("id");
                And then added to the form as so:
                Code:
                filesForm.setFields(pkItem, files);

                Comment


                  #9
                  FYI - we're still working on this. The additional hiddenItem shouldn't actually be required here, and the "add" case should "just work".
                  We see the problem and will follow up when we have it solved.

                  Regards
                  Isomorphic Software

                  Comment


                    #10
                    We've made some changes to address this issue. Please try the next nightly build, dated Dec 5 or above.
                    Fix applied to 5.0 and 5.1d branches.
                    Please note that both the add and the update case should work, and there should be no need for the additional hiddenItem. If you do continue to see problems with this, please be sure to include a test case and steps to reproduce so we can see the issues on our end.

                    Thanks and regards
                    Isomorphic Software

                    Comment

                    Working...
                    X