userBigNum
userBigNum

Reputation: 227

Wicket SelectOption<T> returning null on getDefaultModelObject() call made by Select<T>

My answer to question Dynamic <optgroup> support in wicket included a Select box that used WebMarkupContainer and SelectOptions components for styling.

I am actually trying to use that, in a class that extends Form and uses a bean with a "select" property (among others) as a CompoundPropertyModel in the superclass constructor. Beans of type MyBean can belong to one inner group represented by a Group2Bean, and each of those can in turn belong to one outer group represented by a Group1Bean.

Code (modified to hide confidentialities and DB retrieval) is more-or-less as follows:

HTML code for the Select:

<select wicket:id="select">
    <wicket:container wicket:id="outerRV">
        <optgroup wicket:id="optGroup1">
          <wicket:container wicket:id="rv">
            <optgroup wicket:id="optGroup2">
              <wicket:container wicket:id="selectOptions">
                <option wicket:id="option"></option>
              </wicket:container>
            </optgroup>
          </wicket:container>
        </optgroup>
    </wicket:container>
</select>

Java code for the whole form:

public class MyForm extends Form<FilterBean> {

public MyForm(String id, FilterBean filterBean) {

super(id, new CompoundPropertyModel<FilterBean>(filterBean);

/*
 * ...code to get group1Beans and group2Beans...
 */

/* Select */
Select select = new Select("select");
select.setRequired(true);
add(select);

/* markup repeater for each group1 division */
RepeatingView rvOuter = new RepeatingView("outerRV");
select.add(rvOuter);

for(Group1Bean group1Bean : group1Beans){ /* for each group1 division */

    /* container with unique wicket ID */
    WebMarkupContainer overOptgroup1 = new WebMarkupContainer(rv.newChildId());
    rv.add(overOptgroup1);

    /* outer optgroup, name taken from group1Bean */
    WebMarkupContainer optGroup1 = new WebMarkupContainer("optGroup1");
    overOptGroup.add(optGroup1);
    optGroup1.add(
        new AttributeModifier("label",true,
                              new Model<String>(group1Bean.getName()
        ))
    );

    /* markup repeater for each group2 division */
    RepeatingView rv = new RepeatingView("rv");
    select.add(rv);

    for(Group2Bean group2bean : group2Beans){ /* for each group2 division */

      /* container with unique wicket ID */
      WebMarkupContainer overOptgroup2 =
              new WebMarkupContainer(rv.newChildId());
      rv.add(overOptgroup2);

      /* inner optgroup, name taken from group2Bean and indented */
      WebMarkupContainer optGroup2 = new WebMarkupContainer("optGroup2");
      overOptGroup.add(optGroup2);

      optGroup2.add(new AttributeModifier("style",true,
          new Model<String>("padding-left:15px")));

      optGroup2.add(new AttributeModifier("label",true,
          new Model<String>(group2Bean.getName())));

      /* fetches and displays MyBean options for selected group2 division */
      optGroup2.add(
          new SelectOptions<MyBean>(
              "selectOptions",fetchMyBeansUnder(group2Bean)
              new MyBeanRenderer()
          ).add(new AttributeModifier("style",true,
                   new Model<String>("padding-left="30px")))
      );
    }
}

Problem is, the model's select property doesn't get updated. Pressing a (default) submit button gives me a "select is required" feedback, even if I change my selection on the generated webapp interface, and attempts to link this component to further fail components fail to retrieve a value for the select property.

Tried updating from 1.4.6 to 1.5.6, which has generic Select, the problem didn't get solved though. Extending and fiddling with Select led me to narrow the problem down to the chosen SelectOption returning null when Select's inputConverter() (called after submit button is pressed) calls getDefaultModelObject() on the option.

Any ideas, folks? Many thanks in advance.

Upvotes: 1

Views: 707

Answers (1)

userBigNum
userBigNum

Reputation: 227

Ok, I found it, a silly mistake. Using that constructor for SelectOption, the model's not automatically created for each option, but created by MyBeanRenderer's getModel() method; I'd returned an empty model instead of a model created from the bean argument. I didn't even think it could be the renderer... it was just a matter of changing that one method to the following:

public IModel<T> getModel(T bean){
    return new Model<T>(bean);
}

Still can't believe I spent weeks on this and didn't see this.

Upvotes: 1

Related Questions