Sean
Sean

Reputation: 253

Reusing wicket component in a form

I have built a wicket component that contains input/labels and methods to change presentation (required, enabled, etc.). The components render fine, but what happens is when the form submits I see only 1 form parameter 'input', and it's the last InputRow component.

InputRow.html

<html xmlns:wicket="http://wicket.apache.org">
<head>
    <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
    <wicket:panel>
        <label wicket:id="label">abc: <span class="req">*</span></label>
        <span class="input">
            <input wicket:id="input" type="text" id="name"></input>
        </span>
        <span wicket:id="input_feedback"></span>            
    </wicket:panel>

</body>
</html>

InputRow.java

package com.wicket;

import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;

public class InputRow extends Panel{

    @SuppressWarnings("unused")
    private String id;

    public InputRow(String id, String label) {
        super(id);

        this.id = id;

         Label memberIdLabel = new Label("label",label);
         memberIdLabel.setEscapeModelStrings(false)
            .add(new AttributeAppender("for", new Model<String>(id),""));
         add(memberIdLabel);

        TextField<String> name = new TextField<String>("input");
        name.setType(String.class)
            .setMarkupId(id)
            .setOutputMarkupId(true);
        add(name);

        add(new Label("input_feedback",""));

    }

    public InputRow disable()
    {
        get("input")
            .setEnabled(false)
            .add(new AttributeAppender("class", new Model<String>("disabled"),""));
        get("label")
            .add(new AttributeAppender("class", new Model<String>("disabled"),""));
        return this;
    }

    public InputRow required()
    {
        Model model = (Model)get("label").getInnermostModel();
        StringBuffer label = new StringBuffer((String)model.getObject());
        label.append(" <span class=\"req\">*</span>");
        model.setObject(label);

        ((TextField)get("input")).setRequired(true);
        return this;
    }

    @Override
    protected void onBeforeRender() {
        super.onBeforeRender();
        Label feedback = (Label)get("input_feedback");

        if (get("input").getFeedbackMessage() != null)
        {
            feedback.setDefaultModel(new Model<String>("Required"));
        }
    }


}

Adding to the form component

add(new InputRow("name","Name:").required());

edit I didn't set up a ListView or repeater since I know what rows / fields I want to add to the form at build time.

Upvotes: 2

Views: 2440

Answers (3)

Nicktar
Nicktar

Reputation: 5575

Your InputFields are missing their models. This way, wicket doesn't know where to store the formdata. If you add models to the fields they will be populated automatically.

Upvotes: 1

Andrea Del Bene
Andrea Del Bene

Reputation: 2511

Maybe the problem with your form is that your input text fields have all the same id. Try using attribute 'name' instead of 'id'

Upvotes: 0

Christoph Leiter
Christoph Leiter

Reputation: 9345

There's not just one form parameter submitted. The submits are of the named like name:input, name2:input, ...

But as Nicktar suggests in the comment you should use a model to bind the value of the form component to your entity object. You have to accept an IModel in the constructor and use it in the constructor of TextField.

A better approach to what you are trying to do is to write a Behavior which adds decorating markup for your FormComponent. That way it works for more than just simple text input fields and you can fully customize the instances of your FormComponents.

It could look like this:

public class FormComponentBehavior extends Behavior {

    @Override
    public void bind(Component component) {
        if (!(component instanceof FormComponent)) {
            throw new IllegalArgumentException();
        }
    }

    @Override
    public void beforeRender(Component component) {
        FormComponent<?> fc = (FormComponent<?>) component;
        Response r = component.getResponse();
        r.write("<label" + (fc.isRequired() ? " class='required'" : "") + ">");
        r.write(fc.getLabel().getObject());
        r.write("</label>");
        r.write("<span class='input'>");
    }

    @Override
    public void afterRender(Component component) {
        component.getResponse().write("</span>");
        // if feedback errors write them to markup...
    }
}

Then you have to add this behavior to your FormComponent instances.

Upvotes: 1

Related Questions