Announcement

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

    Setting a multi-value property on a form

    I've been spending a lot of time looking at this; including at the client source-code behind the core SmartGWT classes and here is my question: how you set a multi-value property on a DynamicForm; where the value is either an array of int or an array of String?

    I've tried setting up a ListGrid inside a CanvasItem, constructing a JavaScriptObject from the contents of the ListGrid; and then calling DynamicForm.setValue() but the DynamicForm somehow completely garbles the JSO.

    Here is some sample code:

    Code:
    listGrid.addRecordDropHandler(new RecordDropHandler(){
    
    				@Override
    				public void onRecordDrop(RecordDropEvent event) {
    					
    					Vector<Integer> idList = new Vector<Integer>();
    					
    					//list of existing ids already in selector:
    					int[] exIds = getIds();
    					
    					for(int exId : exIds)
    					{
    						idList.add(new Integer(exId));
    					}
    					
    					//newly added ids
    					ListGridRecord[] addedRecords = event.getDropRecords();
    					
    					for(ListGridRecord addedRecord: addedRecords)
    					{
    						idList.add(addedRecord.getAttributeAsInt("id"));
    					}
    					
    					
    					
    					
    					int[] idArray  = new int[idList.size()];
    					
    					for(int i=0; i<idList.size(); i++)
    					{
    						idArray[i]= idList.get(i).intValue();
    					}
    					
    					JavaScriptObject jsoArray = JSOHelper.convertToJavaScriptArray(idArray);
    					
    					Log.debug("Setting listGridSelector myArray to jsoArray:" + jsoArray);
    				
    			
    					
    					form.setValue("myArray", jsoArray);
    				}
    				
    				
    			});
    DataSource file:

    Code:
    <DataSource
    	ID="myObject"
    	serverType="generic">
    	<fields>
    		<field name="id" type="sequence" hidden="false" primaryKey="true"/>
    		
    		<field name="myArray" type="int" title="My Array" multiple="true"/>
    		
    	</fields>
    	
    	 <serverObject lookupStyle="spring" bean="myObjectDS"/>
    	 
    </DataSource>
    First of all, this doesn't even pass validation - for some reason, the client doesn't seem to recognize that what is in the JSO is actually an array of int - I suspect it sees it as either a straight string or an array of string.

    Changing the type of the myArray in the DataSource file to "text" does allow it to submit:


    Code:
    <DataSource
    	ID="myObject"
    	serverType="generic">
    	<fields>
    		<field name="id" type="sequence" hidden="false" primaryKey="true"/>
    		
    		<field name="myArray" type="text" title="My Array" multiple="true"/>
    		
    	</fields>
    	
    	 <serverObject lookupStyle="spring" bean="myObjectDS"/>
    	 
    </DataSource>
    but now the problem we have is that the DataSource mangles the contents of the JSO value. For instance, while the JSO array contains this:

    Code:
    23:59:12.328 [INFO] [myApp] (-:-) 2010-08-02 23:59:12,327 [DEBUG] Setting listGridSelector myArray to jsoArray:7480,7481,7482,7483,7484

    this is what actually get submitted:

    Code:
    Request #1 (DSRequest) payload: {
        criteria:{
        },
        values:{
          
            myArray:"7,480,7,481,7,482,7,483,7,484"
          
        },
        operationConfig:{
            dataSource:"myObject",
            operationType:"add"
        },
        componentId:"isc_OID_97",
        appID:"builtinApplication",
        operation:"myObject_add",
        oldValues:{
    }
    }
    whereas the request SHOULD look this:

    Code:
    Request #1 (DSRequest) payload: {
        criteria:{
        },
        values:{
          
            myArray:[7480,7481,7482,7483,7484]
          
        },
        operationConfig:{
            dataSource:"myObject",
            operationType:"add"
        },
        componentId:"isc_OID_97",
        appID:"builtinApplication",
        operation:"myObject_add",
        oldValues:{
    }
    }
    The only way I've found of doing this is by disconnecting the listGrid from the DynamicForm; overriding saveUpdate(), calling DynamicForm.getValuesAsRecord(), setting an int Array on that record, then calling form.editRecord() with the new record and then calling super.saveData(). In other words:

    Code:
    @Override
    public void saveData()
    {
      Record recordCopy = getValuesAsRecord();
      recordCopy.setValue("myArray",listGrid.getIds());
      editRecord(recordCopy);
      super.saveData();
    
    }
    This works; but of course it's a total hack.

    I suspect the source of the problem lies in how the setValue() method on the DynamicForm class is put together; namely:

    Code:
      public native void setValue(String fieldName, JavaScriptObject value) /*-{
            var self = this.@com.smartgwt.client.widgets.BaseWidget::getOrCreateJsObj()();
            self.setValue(fieldName, value);
        }-*/;
    whereas the code for the Record.setValue does:

    Code:
     public void setAttribute(String property, int[] value) {
            JSOHelper.setAttribute(jsObj, property, value);
        }
    and

    Code:
     public static native void setAttribute(JavaScriptObject elem, String attr, JavaScriptObject[] value) /*-{
    	    elem[attr] = value;
        }-*/;
    If I understand that code correctly; there's basically no way to insert the contents of a javascript array into a DynamicForm because it assumes that all JavaScriptObjects are single value.

    What we urgently need at this point is for DynamicForm to have a setValue(int[] values) and setValue(String[] values) method; or even better: for FormItem to have a setValue(int[] values) and setValue(String[] values) method.

    #2
    Looks like your assuming that setting multiple="true" means a TextItem (the default editor in this case) begins offering a multi-value editing interface and stored it's internal value as an int. It doesn't do this and by default will end up converting whatever it receives to an atomic value (String), but you can add a parser / formatter pair to do this yourself.

    Having done that, see if it clears up your confusion regarding value management.

    Comment


      #3
      Thanks Isomorphic.

      that helps, but I'm still a bit confused. I understand the point about TextItems not natively being able to edit multivalue data (whether that be an array of String or int). I also see where the valueFormatter and valueParser would come in to parse the data getting set by the dataSource/being submitted to the datasource respectively.

      What isn't clear to me is what I should set the type of the field to in the .ds.xml file; assuming that what I'm submitting/receiving are JavaScriptObjects (which I believe are the only medium available to transmit array data). Obviously, none of the default types would be a good candidate.Should I just leave the type unset?

      Comment


        #4
        Your DataSource-level declaration (type="int" multiple="true") is fine and the validation subsystem understands it. But you need to augment the TextItem behavior before this will be revealed.

        Comment

        Working...
        X