ChambreNoire
ChambreNoire

Reputation: 429

Inheritance issue with Wicket Forms

I'm trying to figure out a reasonable way of dealing with Forms in Wicket (I'm using 6.17) in particular with regards to inheritance and avoiding code duplication.

Here is the typical schema I'm currently working with :

public class PersonEditPanel<T extends Person> extends BasePanel<T> {

    public PersonEditPanel(String id, IModel<T> model) {    
        super(id, model);
        steOutputMarkupId(true);
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();

        add(newPersonForm("form", getModel());
    }

    protected Form newPersonForm(String id, IModel<T> model) {

        return new PersonEditForm(id, model);
    }

    protected class PersonEditForm extends Form<T> {            

        protected PersonEditForm(String id, IModel<T> model) {
            super(id, CompoundPropertyModel.<T>of(model);
        }

        @Override
        protected void onInitialize() {
            super.onInitialize();

            TextField<String> name = new TextField<String>("name") {

                @Override
                public boolean isRequired() {
                    return isNameRequired();
                }
            }; 
            name.add(StringValidator.lengthBetween(2, 40));
            name.setLabel(new ResourceModel("label.name"));

            add(name);

            add(new SimpleFormComponentLabel("nameLabel", name));

            TextField<String> surname = new TextField<String>("surname") {

                @Override
                public boolean isRequired() {
                    return isSurnameRequired();
                }
            }; 
            surname.add(StringValidator.lengthBetween(2, 40));
            surname.setLabel(new ResourceModel("label.surname"));

            add(surname);

            add(new SimpleFormComponentLabel("surnameLabel", surname));

            // and so on ...
        }

        @Override
        protected void onSubmit() {
            PersonEditPanel.this.onSubmit();
        }

        @Override
        protected void onCancel() {
            PersonEditPanel.this.onCancel();
        }
    }

    protected boolean isNameRequired() {
        return true;
    }

    protected boolean isSurnameRequired() {
        return true;
    }

    protected void onSubmit() {}

    protected void onCancel() {}
}

and here's the markup :

<wicket:panel>
    <form wicket:id="form">
        <div>    
            <label wicket:id="nameLabel"></label>
            <input wicket:id="name" type="text"/>
        </div>
        <div>                
            <label wicket:id="surnameLabel"></label>
            <input wicket:id="surname" type="text"/>
        </div>
    </form>
</wicket:panel>

So when I need to edit a sub-class of Person, say Employee, I extend PersonEditPanel as follows :

public class EmployeeEditPanel extends PersonEditPanel<Employee> {

    public EmployeeEditPanel(String id, IModel<Employee> model) {
        super(id, model);
    }

    @Override
    protected Form newPersonForm(String id, IModel<Employee> model) {

        return new PersonForm(id, model) {

            @Override
            protected void onInitialize() {
                super.onInitialize();

                TextField<String> role = new TextField<String>("role") {

                    @Override
                    public boolean isRequired() {
                        return isRoleRequired();
                    }
                }; 
                role.setLabel(new ResourceModel("label.role"));

                add(role);   

                add(new SimpleFormComponentLabel("roleLabel", role));
            }
        };
    }

    protected boolean isRoleRequired() {
        return true;
    }
}

and thus it inherits all of the fields and behaviors defined in the super-classes.

It's slightly awkward if I need to override a validator added to the base PersonEditForm from the EmployeeEditForm but so far that hasn't been a requirement for me...

However this solution still requires me to duplicate markup in the sub-classes as illustrated below :

<wicket:panel>
    <form wicket:id="form">
        <div class="field">    
            <label wicket:id="nameLabel"></label>
            <input wicket:id="name" type="text"/>
        </div>
        <div class="field">                
            <label wicket:id="surnameLabel"></label>
            <input wicket:id="surname" type="text"/>
        </div>
        <div class="field">
            <label wicket:id="roleLabel"></label>
            <input wicket:id="role" type="text"/>
        </div>
    </form>
</wicket:panel>

This is a bit 'meh', especially considering that some entities have way more fields.

I have heard that some people make use of composition with FormComponentPanels which would certainly be helpful in rendering some entities reuseable such as Address entities etc. but I'm not sure how this would work within the inheritance model.

Any comments and/or advice from more seasoned Wicket developpers than I would be most welcome!

Many thanks in advance,

Anthony

Upvotes: 0

Views: 220

Answers (1)

Roman Grigoriadi
Roman Grigoriadi

Reputation: 1928

You should check <wicket:child /> / <wicket:extends> if you want to reuse your markup in inheritance.

If you want to have reusable set of form fields, you can place them in a panel instead of parent form and than insert this panel in all forms you wish.

Upvotes: 1

Related Questions