CustomField - customizing form field look and functionality

The version 0.7 of CustomField is now out, with many new examples and features.
This should take away many of the pains when using Vaadin forms while waiting for Vaadin 7.

In addition to small improvements to the old CustomField class, there is now a new class FieldWrapper. It delegates most functionality to another field, with the option of using a custom layout around the wrapped field. Also, value conversions and overriding some of the functionality are supported by FieldWrapper.

An on-line demo is available
here
.

For more information, downloads, a link to the sources etc., see
the directory entry
. There are still some rough edges and known limitations in this version, please report any issues/bugs encountered in this thread.

FYI, I had various issues with using the CustomField 0.7.2 FieldWrapper related to validation and error messages. I posted a summary, as well as work-arounds, here:

http://vaadin.com/forum/-/message_boards/message/212776

Cheers,
Raman

Where can I find sample code for the examples given in the online demo?

I want to apply CustomField on a ComboBox. But for some reason I get compile time errors when I add valuechangelistener to my combobox. I’m using Vaadin 6.5 and customfield 0.8.2. If I can find the source for the demo examples I could work it out from there.

Thanks
Nabeel

As mentioned in the original post, the
Directory page for CustomField
contains a link to
the project with the source code
(including demos).

Thanks for great add-on!

Can You add, please, to your addon ItemConverter (see
why
)

ItemConverter is a simple Item wrapper, which delegates all calls to other item, but one can “wrap” some properties in PropertyConverter.

It can be used in Forms and custom containers.

Example based on PropertyFormatter:


/**
 * It's hard to use {@link PropertyFormatter} alone, so ItemFormatter allows to wrap your Item and replace several properties with
 * formatted properties.
 *
 * @author Andrew Fink [aprpda@gmail.com]
 http://magicprinc.blogspot.com
 *
 * @see com.vaadin.data.util.PropertyFormatter
 * seeorg.vaadin.customfield.PropertyConverter
 */
public class ItemFormatter implements Item, Item.PropertySetChangeNotifier, Cloneable, Item.Viewer {
	private Item item;
	private Map<Object, PropertyFormatter> instances = Collections.emptyMap();
	private Map<Object, Class<PropertyFormatter>> classes = Collections.emptyMap();


	public ItemFormatter () {}//new

	public ItemFormatter (Item item) { setItemDataSource(item);	}//new

	public static ItemFormatter of (Item newDataSource) { return new ItemFormatter(newDataSource);}


	@Override	public void setItemDataSource (Item newDataSource) { this.item = newDataSource;}

	@Override	public Item getItemDataSource () { return item;}


	public void setFormatterInstances (final Map<Object, PropertyFormatter> asis) {instances = asis;}


	public void setFormatterClasses (final Map<Object, Class<PropertyFormatter>> classes) {this.classes = classes;}


	@Override	public Property getItemProperty (Object pid) throws IllegalStateException {
		final Property property = item.getItemProperty(pid);
		if (property == null) { return null; }//not exists

		PropertyFormatter propertyFormatter = instances.get(pid);
		if (propertyFormatter != null) {
			propertyFormatter.setPropertyDataSource(property);
			return propertyFormatter;
		}

		Class<PropertyFormatter> propertyFormatterClass = classes.get(pid);
		if (propertyFormatterClass != null) {
			try {
				propertyFormatter = propertyFormatterClass.newInstance();
			} catch (InstantiationException e) {
				throw new IllegalStateException("getItemProperty: can't create "+propertyFormatterClass.getName()+" instance for PID="+pid, e);
			} catch (IllegalAccessException e) {
				throw new IllegalStateException("getItemProperty: can't create "+propertyFormatterClass.getName()+" instance for PID="+pid+": IAE", e);
			}//t

			propertyFormatter.setPropertyDataSource(property);
			return propertyFormatter;
		}//i

		return property;//as is
	}//getItemPropertyIds


	@Override	public Collection<?> getItemPropertyIds () { return item.getItemPropertyIds();}


	@Override	public boolean addItemProperty (Object pid, Property property) throws UnsupportedOperationException {
		return item.addItemProperty(pid, property);
	}


	@Override	public boolean removeItemProperty (Object pid) throws UnsupportedOperationException {
		return item.removeItemProperty(pid);
	}


	@Override public void addListener (PropertySetChangeListener listener) {
		if (item instanceof PropertySetChangeNotifier) {
			((PropertySetChangeNotifier) item).addListener(listener);
		}
	}//addListener


	@Override public void removeListener (PropertySetChangeListener listener) {
		if (item instanceof PropertySetChangeNotifier) {
			((PropertySetChangeNotifier) item).removeListener(listener);
		}
	}//removeListener
}//ItemFormatter

Hi,
I’ve tried using the NestedForm per the example source code. Everything works fine until I do setReadOnly on the form that encloses the CustomField that encloses the NestedForm. The call succeeds, but the subsequent repaint fails with a ConcurrentModificationException.

Any ideas?

I finally got around to adding this class to the CustomField version control, and added you committer access to the CustomField project.

I might make sense to use a PropertyConverter instead of a PropertyFormatter for more flexibility about types. Also, a little example of usage in the demo package would not hurt. If you want to make the changes yourself, contact me when you believe a new version of the add-on should be made and published, although I cannot guarantee being able to do it immediately.

Note that I did restructure the packages in the add-on, and added some new helper classes from another project - you might also be interested in taking a look at the ID-BEAN and Set-Set converters they provide.

Wow! It’s a great honour for me.
I’ll take some time for research.

I did some changes http://code.google.com/p/customfield/source/list

May be some source formatting rules are broken, I didn’t found project’s style config (and I use IDEA).
But at functional level looks good for me…

The custom field is very hard to learn!
I am new to vaadin and have the common requirement to build an form that update an object graph, like Person and Address, I checkout the source and get lost in the examples.

Let compare with JSF form, simple create the ui field and set the value like this:

<h:form>
<h:input value=“#{personCrlBean.person.name}”/>
<h:input value=“#{personCrlBean.person.address.street}” />
<h:commandButton value=“Save” action=“#{personBean.save}” />
</h:form>

or if the address is a one-to-many association, I can update address as a property on control bean and do the add in save method:

<h:form>
<h:input value=“#{personCrlBean.person.name}”/>
<h:input value=“#{personCrlBean.address.street}” />
<h:commandButton value=“Save” action=“#{personBean.save}” />
</h:form>

The save method can look like:

person.getAddress.add(address);
persist(person);

The key here is that the jsf updates the model graph with the value of input element no matter how deep the object graph are.

But in vaadin until now the only way to update and access a graph os objets in forms is to create a Custom Field for every Class in the graph and extend the DefaultFieldFactory to change the field with the custom field that return the object. I know that is a best approach to do reusable forms but is hundreds of lines of more code effort. The advantage of Custom Field + Field Factory is if I want use the Custom Address Form with another pojo like Cliente, that have an address, is just use them.

I will keep moving, but I think that the example can be more simpler in the implementation, don’t worry about reusable code, do a simple example first and update to a new more reusable and advanced example later. This is because I have to understand many classes that form the pieces of the entire logic of application before understand what I need.

For novices is terrible, maybe good practices to learn but not didactic.

I was quite surprised that updating the property value to which my CustomField was bound did not update the field itself. The reason seems to be that valueChange() does not call setInternalValue(). Is this intentional or is it a bug?

Whats the plan for this component? I used it alot in version 6, but now upgrading to vaadin 7. Is it going to be fixed for vaadin 7 or is there a better way of doing this in vaadin 7?

Thanks
Paul.

There is now a CustomField integrated in Vaadin 7. Internally, it works quite differently from the add-on (almost a rewrite), though, as there is support for converters etc. in AbstractField.

Some extra methods will be removed from Vaadin 7 CustomField in the next release.

Hello,

Is that possible if I would like to have a another button in nested form (Add New Address) so that another set of Address can be added to Person. N finally, Person has a list of Address.

I also see the example in the Book of Vaadin with CustomField of Vaadin7, however that could not help me because 'm still using Vaadin 6.8

I hope I got some suggestions from this Forum.

Right now I really got stuck in that. so any help is highly appreciated! the

Unfortunately DEMO disappeared from SVN…

The add-on project for Vaadin 6 was split into two add-ons: CustomField and CustomField Utils. All the source code can be found
here
under those two projects (src/test/java/…), whereas the old demo project is now empty.

You can take a look at
this
and
this
package.

Henri, is there a plan to make CustomField Vaadin 7 compatible?