Can't do a short example, but what I was imagining goes something like I've detailed below.
I've used blindingly obvious names (I hope) which you could probably cut down, and I haven't included Composite, just gone for a straight extend of FlowPanel in order to simplify the code a bit. Styles have been hard-coded where normally I'd be adding and removing styles. It's just to show what I had in mind.
Now I realise that this is an awful lot of work just to get an email address :-) but bear in mind that now adding, say, a phone number to the contact details would require a lot less effort. The classes are all reusable. If there's a bug, it's pretty obvious where to look. And none of the classes are unmanageably large (which they might easily get if you hadn't split them up).
Changing the layout doesn't affect anything else. Changing a textbox for a textarea can be done in the one class. You can swap the submit button for an image in one class. You can have different views for different situations or give your users a choice of skins.
Should anyone wants a zip of the project, let me know.
Ian
=================================================================
So...
You have a registration panel of some sort. In its view along with other things, it includes a contact details panel.
The contact details panel includes, well, contact detail input widgets. Amongst them is one for an email address.
The Registration panel is instigated like this:
new Registration(new RegistrationView(this));
where 'this' is the view or whatever you want to add it to.
The Registration class looks like this:
public class Registration implements ClickHandler
{
private RegistrationViewInterface view;
public Registration(RegistrationViewInterface view)
{
this.view = view;
view.getSubmittingWidget().addClickHandler(this);
}
interface RegistrationViewInterface
{
// Submitting widget
HasClickHandlers getSubmittingWidget();
// Check if the input is valid
boolean inputIsAcceptable();
// Flag errors (if any)
void showErrors();
}
@Override
public void onClick(ClickEvent event)
{
/*
* Show any errors (and remove error indicators if OK)
*/
view.showErrors();
/*
* If errors, then give up
*/
if(!view.inputIsAcceptable()) return;
/*
* Input is acceptable
*/
}
}
The Registration view
public class RegistrationView extends FlowPanel implements RegistrationViewInterface
{
private Button submit = new Button("Submit");
ContactDetails contactDetails;
public RegistrationView(HasWidgets parentView)
{
parentView.add(this);
/*
* A few labels as placeholders for other input areas
*/
add(new Label("First Name Input Here"));
add(new Label("Last Name Input Here"));
/*
* Now add a contact details area
*/
contactDetails = new ContactDetails(new ContactDetailsView(this));
/*
* And the submit button
*/
add(submit);
}
@Override
public HasClickHandlers getSubmittingWidget()
{
return submit;
}
@Override
public boolean inputIsAcceptable()
{
boolean returnValue = true;
returnValue &= contactDetails.inputIsAcceptable();
/*
* Also check anything else on the screen here
*/
return returnValue;
}
@Override
public void showErrors()
{
contactDetails.showErrors();
/*
* Also show errors for anything else on the screen here
*/
}
}
So you have a registration screen which includes a contact details panel which can be reused elsewhere.
Contact details
public class ContactDetails
{
private ContactDetailsViewInterface view;
public ContactDetails(ContactDetailsViewInterface view)
{
this.view = view;
}
interface ContactDetailsViewInterface
{
InputEmail getEmail();
/*
* Add other contact information requirements here
*/
void showErrors();
}
public boolean inputIsAcceptable()
{
boolean returnValue = true;
returnValue &= view.getEmail().inputIsAcceptable();
/*
* Check other contact information requirements here
*/
return returnValue;
}
public void showErrors()
{
view.showErrors();
}
}
Contact details view
public class ContactDetailsView extends FlowPanel implements ContactDetailsViewInterface
{
InputEmail inputEmail;
public ContactDetailsView(HasWidgets parentView)
{
parentView.add(this);
/*
* A few labels as placeholders for other input areas
*/
add(new Label("Land Line Input Here"));
add(new Label("Mobile No Input Here"));
/*
* And an email input widget
*/
inputEmail = new InputEmail(new InputEmailView(this));
}
@Override
public InputEmail getEmail()
{
return inputEmail;
}
@Override
public void showErrors()
{
inputEmail.showErrors();
}
}
The email input
public class InputEmail
{
private InputEmailViewInterface view;
public InputEmail(InputEmailViewInterface view)
{
this.view = view;
}
interface InputEmailViewInterface
{
String getEmailText();
void showError(boolean error);
/*
* You might want also to be able to set text, flag if optional or not
* etc.
*/
}
public boolean inputIsAcceptable()
{
return BusinessRules.validateEmail(view.getEmailText());
}
public String getEmail()
{
return view.getEmailText();
}
public void showErrors()
{
view.showError(!BusinessRules.validateEmail(view.getEmailText()));
}
}
And the email input view
public class InputEmailView extends FlowPanel implements InputEmailViewInterface
{
private TextBox textbox = new TextBox();
public InputEmailView(HasWidgets parentView)
{
parentView.add(this);
add(new Label("Email"));
add(textbox);
}
@Override
public String getEmailText()
{
return textbox.getText();
}
@Override
public void showError(boolean error)
{
if(error)
{
textbox.getElement().getStyle().setProperty("border", "2px solid #f00");
}
else
{
textbox.getElement().getStyle().setProperty("border", "2px inset #eee");
}
}
}