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