I've been using SmartClient GWT for a few months, and I've been really impressed. The functionality is quite powerful and software skillfully crafted and designed.
I have questions on how to use the FormItemValueParser. I have a TextItem that I've extended, and it is for child records of a parent record. I'd like this TextItem to display a comma separated list of codes from for the child records, and for the user to be able to quickly enter these codes as a comma separated list.
For example, I have a form that lets you edit a country, and the TextItem mentioned above would be for the states in the country. The user could enter a list of comma separated states, and the FormItemValueParser would create the underlying records for each state. If the user entered "CO,FL,MA,NY" into the TextItem, 4 records would be created.
This works for me if the TextItem has been pre-populated with an existing record. I can add and remove codes, and the parser works fine. However, I can't get it to work if the field is initially empty. I've tried returning a myriad of JavaScriptObjects, Records, arrays of either, etc, from my FormItemValueParser.parseValue(), and I just get exceptions back.
So my question is, what is parseValue() expected to return when the TextItem is for a field that represents child data (multiple values)?
Below is my code that shows a simple example of what I'm doing. It is self contained. I tried to keep it short as possible, given the complexity of what I need to do.
I'm using Smart GWT Pro 2.1, GWT 2.0.3, Firefox 3.6.6 on XP sp3.
Thanks for your feedback!
Chris
I have questions on how to use the FormItemValueParser. I have a TextItem that I've extended, and it is for child records of a parent record. I'd like this TextItem to display a comma separated list of codes from for the child records, and for the user to be able to quickly enter these codes as a comma separated list.
For example, I have a form that lets you edit a country, and the TextItem mentioned above would be for the states in the country. The user could enter a list of comma separated states, and the FormItemValueParser would create the underlying records for each state. If the user entered "CO,FL,MA,NY" into the TextItem, 4 records would be created.
This works for me if the TextItem has been pre-populated with an existing record. I can add and remove codes, and the parser works fine. However, I can't get it to work if the field is initially empty. I've tried returning a myriad of JavaScriptObjects, Records, arrays of either, etc, from my FormItemValueParser.parseValue(), and I just get exceptions back.
So my question is, what is parseValue() expected to return when the TextItem is for a field that represents child data (multiple values)?
Below is my code that shows a simple example of what I'm doing. It is self contained. I tried to keep it short as possible, given the complexity of what I need to do.
Code:
package com.smartgwt.sample.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
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.types.DSDataFormat;
import com.smartgwt.client.types.FieldType;
import com.smartgwt.client.util.JSOHelper;
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.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemValueFormatter;
import com.smartgwt.client.widgets.form.FormItemValueParser;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.layout.VLayout;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class BuiltInDS implements EntryPoint
{
/**
* 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();
}
} );
final DynamicForm form = new DynamicForm();
DataSource ds = CountryDS.getInstance();
form.setDataSource( ds );
TextItem countryName = new TextItem( "countryName" );
MultiValueItem state = new MultiValueItem( "state", "States" );
state.setEditorValueParser( multiValueParser() );
state.setEditorValueFormatter( multiValueFormatter() );
form.setFields( countryName, state );
final IButton populateButton = new IButton( "Populate" );
populateButton.addClickHandler( new ClickHandler()
{
public void onClick(com.smartgwt.client.widgets.events.ClickEvent event)
{
Record record = new Record();
record.setAttribute( "countryCode", "US" );
record.setAttribute( "countryName", "United States" );
Record states[] = new Record[2];
states[0] = new Record();
states[0].setAttribute( "stateName", "Colorado" );
states[0].setAttribute( "stateCode", "CO" );
states[1] = new Record();
states[1].setAttribute( "stateName", "Florida" );
states[1].setAttribute( "stateCode", "FL" );
record.setAttribute( "state", states );
form.editRecord( record );
}
} );
final IButton validateButton = new IButton( "Validate" );
validateButton.addClickHandler( new ClickHandler()
{
public void onClick(com.smartgwt.client.widgets.events.ClickEvent event)
{
SC.warn( "getValue(state)=" + form.getField( "state" ).getValue() );
form.validate();
}
} );
VLayout main = new VLayout();
main.addMember( form );
main.addMember( populateButton );
main.addMember( validateButton );
main.draw();
}
public FormItemValueParser multiValueParser()
{
FormItemValueParser valueParser = new FormItemValueParser()
{
@Override
public Object parseValue(String value, DynamicForm form, FormItem item)
{
JavaScriptObject jso = (JavaScriptObject) item.getValue();
if ( jso == null )
{
Record items[] = new Record[ 1 ];
items[ 0 ] = new Record();
items[ 0 ].setAttribute( "stateCode", value );
//return JSOHelper.convertToJavaScriptArray( items );
// The field was empty, and the user is entering data for the first time
// The item therefore has no JavaScriptObjects yet
// Not sure what to return here -
return null;
}
parse( jso, value );
return jso;
}
public void parse(JavaScriptObject parsed, String value)
{
String idents[] = value.split( "," );
int parsedLength = JSOHelper.arrayLength( parsed );
if ( parsedLength > idents.length )
{
for ( int j = idents.length ; j < parsedLength ; j++ )
{
removeLast( parsed );
}
}
for ( int i = 0 ; i < idents.length ; i++ )
{
JavaScriptObject existing = JSOHelper.getJSOArrayValue( parsed, i );
if ( ( existing == null )
|| ( idents[ i ].equals( JSOHelper.getAttribute( existing, "stateCode" ) ) == false ) )
{
JavaScriptObject jso = JSOHelper.createObject();
JSOHelper.setAttribute( jso, "stateCode", idents[ i ].toUpperCase() );
JSOHelper.arraySet( parsed, i, jso );
}
}
}
public native void removeLast(JavaScriptObject array) /*-{
array.length = array.length - 1;
}-*/;
};
return valueParser;
}
public FormItemValueFormatter multiValueFormatter()
{
FormItemValueFormatter valueFormatter = new FormItemValueFormatter()
{
@Override
public String formatValue(Object value, Record record, DynamicForm form, FormItem item)
{
String fieldname = "stateCode";
if ( value != null && JSOHelper.isJSO( value ) )
{
String str = "";
try
{
JavaScriptObject jso = (JavaScriptObject) value;
if ( JSOHelper.isArray( jso ) )
{
int len = JSOHelper.getArrayLength( jso );
if ( len > 0 )
{
JavaScriptObject elem1 = (JavaScriptObject) JSOHelper.arrayGetObject( jso, 0 );
str += JSOHelper.getAttribute( elem1, fieldname );
if ( len > 1 )
{
for ( int ix = 1 ; ix < len ; ix++ )
{
JavaScriptObject elem = (JavaScriptObject) JSOHelper.arrayGetObject( jso, ix );
str += "," + JSOHelper.getAttribute( elem, fieldname );
}
}
}
}
}
catch ( Throwable t )
{
str = "";
}
return str;
}
return "";
}
};
return valueFormatter;
}
private class MultiValueItem extends TextItem
{
public MultiValueItem(String name, String title)
{
super( name, title );
setName( name );
setTitle( title );
setEditorType( this );
FormItemIcon formItemIcon = new FormItemIcon();
setIcons( formItemIcon );
}
}
private static class CountryDS extends DataSource
{
// The DataSource would normally be defined external to any classes that use it.
private static CountryDS instance = null;
public static CountryDS getInstance()
{
if ( instance == null )
{
instance = new CountryDS( "countryDS_XML" );
}
return instance;
}
public CountryDS(String id)
{
setID( id );
setDataFormat( DSDataFormat.XML );
setRecordXPath( "/List/country" );
DataSourceField countryCodeField = new DataSourceField( "countryCode", FieldType.TEXT, "Code" );
DataSourceField countryNameField = new DataSourceField( "countryName", FieldType.TEXT, "Country" );
DataSourceField capitalField = new DataSourceField( "capital", FieldType.TEXT, "Capital" );
DataSourceField stateField = new DataSourceField();
stateField.setName( "state" );
stateField.setTypeAsDataSource( StateDS.getInstance() );
stateField.setTitle( "States" );
setFields( countryCodeField, countryNameField, capitalField, stateField );
setDataURL( "ds/test_data/country.data.xml" );
}
}
private static class StateDS extends DataSource
{
// The DataSource would normally be defined external to any classes that use it.
private static StateDS instance = null;
public static StateDS getInstance()
{
if ( instance == null )
{
instance = new StateDS( "stateDS_XML" );
}
return instance;
}
public StateDS(String id)
{
setID( id );
setDataFormat( DSDataFormat.XML );
setRecordXPath( "/List/country/state" );
DataSourceField stateCodeField = new DataSourceField( "stateCode", FieldType.TEXT, "Code" );
DataSourceField stateNameField = new DataSourceField( "stateName", FieldType.TEXT, "State" );
DataSourceField capitalField = new DataSourceField( "capital", FieldType.TEXT, "Capital" );
setFields( stateCodeField, stateNameField, capitalField );
setDataURL( "ds/test_data/country.data.xml" );
}
}
}
Thanks for your feedback!
Chris
Comment