Several beginner problems (Validation concept, Selecting table rows)

Hey guys,

I’m new to vaadin. I really like it but I struggle with a few problems. I hope you can help me out here :slight_smile:


Data model

The data model is very simple:

I have a collection of MBeans and each MBeans has got several attributes of type Attribute, also stored in a Collection.


UI

I build a ui for it, which looks like this:

In the upper table the MBean-collection is shown. I bound a BeanItemContainer to the table.
In the lower table the Attribute-Collection of the selected MBean (of the upper table) is shown.
So after selecting one element from upper table the container of lower table is updated.
Both works fine for me.

I added for both tables a FieldFactory so that only specific columns are editable.
Following code segment is a snippet from the MBeansTable (upper table).


@Override
			public Field createField(Container container, Object itemId, Object propertyId, Component uiContext) {
				if (propertyId.toString().equals("name")) {
					final TextField tf = new TextField();
                                        //add some validators
					tf.addValidator(...);
					tf.setImmediate(true);
					return tf;
				}
				//other columns....
				return null;
			}

The problem with the field factory above is, that no validation is done during changing text in the text field.
I solved that by adding a TextChangeListener to each textfield. The TextChangeListener looks like:


public class SimpleTextChangedListener implements FieldEvents.TextChangeListener {

	private final Map<Field, Collection<InvalidValueException>> errors = new HashMap<Field, Collection<InvalidValueException>>();

@Override
	public void textChange(TextChangeEvent event) {
		if (event == null || !(event.getSource() instanceof Field)) return;
		Field field = (Field) event.getSource();			
		handleEvent(field, event);
		handleErrors(field);
	}

	private void handleEvent(Field field, TextChangeEvent event) {
		if (errors.get(field) == null) errors.put(field, new ArrayList<InvalidValueException>());
		errors.get(field).clear();
		for (Validator v : field.getValidators()) {
			try {
				v.validate(event.getText());
			} catch (InvalidValueException ex) {
				errors.get(field).add(ex);
			}
		}
	}



	private void handleErrors(Field field) {
            Exception ex = Iterables.getFirst(errors.get(field), null);
			field.setComponentError(null);//reset
			if (ex == null) return; //we are done here
			field.setComponentError(new UserError(ex.getMessage()));
	}
}


The problems

Problem1:
Is it really necessary to register a TextChangeListener to perform immediate validation of input?
Do I really have to do the validation myself?
Is there a better solution?
I tried several listener approaches but none was successfull.
At first I thought ValueChangeListener is the right answer, but a ValuechangeEvent is only thrown AFTER the textfield looses its focus
So may I miss something?

Problem2:
Another problem is how can I realize this feature:
If an user inputs wrong data in the alias text field in the lower table how can I show an error icon in the MBeans table above?

Problem3:
If I click on a non editable column the row is selected (OK)
But if I directly click in the textfield to edit, the row is not selected (NOT OK).
Is it possible to select the row? And how do I do that, I have absolutely no idea. I guess I have to perform some additional data to the textfield?

I appreciate any input on this topic

kind regards
.zip

I think I got most of the answers by myself.

[b]
Problem 1:

[/b]I don’t have to do the validation myself.
I add a TextChangeListener to the TextField and then simply set the value of the component to the events text.


TextField tf = new TextField();
tf.addListener(new FieldEvents.TextChangeListener {
	@Override
	public void textChange(TextChangeEvent event) {
		if (!(event.getSource() instanceof TextField)) return; //nothing to do
		((TextField) event.getSource()).setValue(event.getText()); //trigger validation
	});

But I may have to deal with performance problems.
Because the validation is made on the server.
I deal with that later

[b]
Problem 2:

[/b]I got a solution for that.
I set setSelectable(false) on the table and register an ItemClickListener to the table to do the selection of values myself.


final Table table = new Table();
//....
table.setSelectable(false);
table.addListener(new ItemClickEvent.ItemClickListener() {

            @Override
            public void itemClick(ItemClickEvent event) {
                if (condition) {
                    showErrorToUser();
                } else {
                   table.select(event.getItemId());
                }
            }
        });

I still struggle with the styling of the selected row, because it is not shown as selected.

[b]
Problem 3:

[/b]I did 2 things in the FieldFactory

  1. tell the TextField via setData(itemId) which itemId it belongs to

TextField tf = new TextField();
tf.setData(itemId)
  1. register a FocusListener to the TextField which then selects the row in the above table

tf.addListener(new FocusListener() {
                @Override
                public void focus(FocusEvent event) {
                    outerTable.select(((AbstractComponent) event.getSource()).getData());
                }
            });

Kind regards
.zip