blob: a4403ee4f8b2f457795b715965610bb25c352937 [file] [log] [blame]
A component should be self-contained. The user of a component should neither have to know nor care about its internal structure. She should just be familiar with its external interfaces and its documentation in order to be able to use it. This means in detail: Every component that extends Wicket's own Panel type (thus is a Panel itself) must provide its own HTML template. In contrast, when a component extends the classes @WebMarkupContainer@ or @Form@, there is no HTML template. This implies that you should add components through composition in @WebMarkupContainer@ or @Form@.
*Listing 1:*
{code}
// Poor component
public class RegistrationForm extends Form<Registration> {
public RegistrationForm(String id, IModel<Registration> regModel) {
super(id, new CompoundPropertyModel<Registration>(regModel))
// Wrong: RegistrationForm provides its own components
add(new TextField("username"));
add(new TextField("firstname"));
add(new TextField("lastname"));
}
}
{code}
This snippet is an example for a poor component. The user of the @RegistrationForm@ must know the internal structure of the markup and component in order to use it.
*Listing 2:*
{code}
public class RegistrationPage extends Page {
public RegistrationPage(IModel<Registration> regModel) {
Form<?> form = new RegistrationForm("form");
form.add(new SubmitButton("register") {
public void onSubmit() {
// do something
}
});
add(form);
}
}
{code}
{code:html}
<html>
<body>
<form wicket:id="form">
<!-- These are internal structure information from RegistrationForm -->
Username <input type="text" wicket:id="username"/>
First name <input type="text" wicket:id="firstname"/>
Last name <input type="text" wicket:id="lastname"/>
<!-- Above new components from page which the user knows -->
<input type="submit" wicket:id="register" value="Register"/>
</form>
</body>
</html>
{code}
The code above shows the usage of the poor component in the @RegistrationPage@. You can see that the input fields @firstname@, @lastname@ and @username@ get used, even though these components are not added explicitly to the @RegistrationPage@. Avoid this, because other developers cannot directly see that the components were added in @RegistrationPage@ class.
*Listing 3:*
{code}
// Good component
public class RegistrationInputPanel extends Panel{
public RegistrationInputPanel(String id, IModel<Registration> regModel) {
super(id, regModel);
IModel<Registration> compound = new CompoundPropertyModel<Registration(regmodel)
Form<Registration> form = new Form<Registration>("form", compound);
// Correct: Add components to Form over the instance variable
form.add(new TextField("username"));
form.add(new TextField("firstname"));
form.add(new TextField("lastname"));
add(form);
}
}
{code}
{code:html}
<html>
<body>
<wicket:panel>
<form wicket:id="form">
Username <input type="text" wicket:id="username"/>
First name <input type="text" wicket:id="firstname"/>
Last name <input type="text" wicket:id="lastname"/>
</form>
</wicket:panel>
</body>
</html>
{code}
Now we have a properly encapsulated input component which provides its own markup. Furthermore you can see the correct usage of a Wicket @Form@. The components get added by calling @form.add(Component)@ on the instance variable. On the other hand, it is allowed to add behaviours and validators over inheritance, because those do not have markup ids which must be bound.
With that, the usage of @RegistrationInputPanel@ is much more intuitive. There is no markup of other embedded components present anymore, just markup of components which get directly added. The @RegistrationPage@ provides its own form that delegates the submit to all Wicket nested forms which are contained in the component tree.
*Listing 4:*
{code}
public class RegistrationPage extends Page {
public RegistrationPage(IModel<Registration> regModel) {
Form<?> form = new Form("form");
form.add(new RegistrationInputPanel("registration", regModel);
form.add(new SubmitButton("register") {
public void onSubmit() {
// do something
}
});
add(form);
}
}
{code}
{code:html}
<html>
<body>
<form wicket:id="form">
<div wicket:id="registration">
Display the RegistrationInputPanel
</div>
<input type=&rdquo;submit&rdquo; wicket:id="register" value="Register"/>
</form>
</body>
</html>
{code}