CONTACT FORM running!!! 7.1.6

Thanks to Marko Grönroos who gave me this link

http://demo.vaadin.com/book-examples-vaadin7/book#application.errors.error-indicator.form

The sample was not running… NORMAL!

I was forced to make some corrections!

I gave you my work. If someone may complete the work with icons error, error label for each fields… i will appreciate.

May be a better way to get the fields…


package com.bontirage.extracteur.windows.contact;

import com.vaadin.data.Item;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.data.validator.EmailValidator;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.server.UserError;
import com.vaadin.ui.Button;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

/**
 * @author Philippe Baumard
 */
@SuppressWarnings("serial")
public class CommanderContact extends VerticalLayout {
    interface ErrorDisplay {
        void setError(String error);
        void clearError();
    }
    class ErrorfulFieldGroup extends FieldGroup {
        
        private ErrorDisplay errorDisplay;

		public ErrorfulFieldGroup(Item item) {
            super(item);
        }

        public void setErrorDisplay(ErrorDisplay errorDisplay) {
            this.errorDisplay = errorDisplay; 
        }
        
        @Override
        public void commit() throws CommitException {
            try {
                super.commit();
                if (errorDisplay != null)
                    errorDisplay.clearError();
            } catch (CommitException e) {
                if (errorDisplay != null)
                    errorDisplay.setError(e.getCause().getMessage());
                throw e;
            }
        }
    } 
    class ErrorLabel extends Label implements ErrorDisplay {
        public ErrorLabel() {
            setVisible(false);
        }
        
        public void setError(String error) {
            setValue(error);
            setComponentError(new UserError(error));
            setVisible(true);
        }

        public void clearError() {
            setValue(null);
            setComponentError(null);
            setVisible(false);
        }
    }
    class MyForm extends CustomComponent {
        TextField email = new TextField("Email");
        TextField object = new TextField("Object");
        TextArea message = new TextArea("message");        
        
        public MyForm(Item item) {
            setCaption("My Form");

            VerticalLayout content = new VerticalLayout();

            // Configure fields
            email.setRequired(true);
            email.setRequiredError("Email may not be empty");
    		email.setWidth("300px");
    		email.setMaxLength(50);
            email.addValidator(new EmailValidator("Invalid email address"));
            email.setImmediate(true);
            email.setValidationVisible(true);
 
           
            object.setRequired(true);
            object.setRequiredError("Object may not be empty");
    		object.setWidth("400px");
    		object.setMaxLength(80);
            object.addValidator(new StringLengthValidator("Object must be between 5 and 80 characters", 5, 80, true));
            object.setImmediate(true);
            object.setValidationVisible(true);
         
            message.setRequired(true);
            message.setRequiredError("Message may not be empty");
    		message.setWidth("400px");
    		message.setRows(10);
    		message.setMaxLength(1024);
            message.addValidator(new StringLengthValidator("Object must be between 5 and 1024 characters", 5, 1024, true));
            message.setImmediate(true);
            message.setValidationVisible(true);

            
            // Build the form 
            FormLayout form = new FormLayout();
            form.addComponent(email);
            form.addComponent(object); 
            form.addComponent(message);              
            content.addComponent(form);
            
            // Bind the form
            final ErrorfulFieldGroup binder = new ErrorfulFieldGroup(item);
            binder.setBuffered(true);
            binder.bindMemberFields(this);

            // Have an error display
            final ErrorLabel formError = new ErrorLabel();
            formError.setWidth(null);
            content.addComponent(formError);
            binder.setErrorDisplay(formError);
            
            // Commit button
            Button ok = new Button("OK");
            ok.addClickListener(new ClickListener() {
                @Override
                public void buttonClick(ClickEvent event) {
                    try {
                        binder.commit();   

                        System.out.println(email.getValue());
                        System.out.println(object.getValue());
                        System.out.println(message.getValue()); 
                        
                    } catch (CommitException e) {
                    }
                }
            });
            content.addComponent(ok);
            
            setCompositionRoot(content);
        }
    }
   
	public CommanderContact() {


                PropertysetItem item = new PropertysetItem();
                item.addItemProperty("email", new ObjectProperty<String>(""));
                item.addItemProperty("object", new ObjectProperty<String>(""));
                item.addItemProperty("message", new ObjectProperty<String>(""));
                
                MyForm form = new MyForm(item);
            
                addComponent(form);
 
    }
}

I cannot understand why this code is not good for TextArea field!

item.addItemProperty("message", new ObjectProperty<TextArea>(""));

The value of the property is not the field but the text content (String), and you are giving it a String value. The property could e.g. be bound to several fields of different types, where updating one field triggers updates of the others via the property etc.

There are some cases where you actually want to use a component as a property value type for table cell contents or such, but those are an exception rather than the rule and often there are better ways to handle situations where you might consider doing so.

As for the rest, I didn’t read through all the code in detail but I think at least some of the repeated code could be factored out into a superclass for your forms, perhaps with helper methods etc. Everything related to required could be handled with one call, everything related to validation with one call, setImmediate() done automatically etc. Not everybody has the same needs (e.g. in many applications most field sizes might not be set explicitly but automatically computed based on the layout size) but if your application has similar needs in many locations, by all means factor them out to a common implementation.