Dynamic <optgroup> support in wicket

丶灬走出姿态 提交于 2019-12-04 07:35:39

Use two nested repeaters to iterate over your groups and options:

<select wicket:id="select">
    <optgroup wicket:id="group">
        <option wicket:id="option"></option>
    </optgroup>
</select>

I have had basically the same problem. After a few days looking for a short solution, I believe what works best, for maximum flexibility, is using repeaters, containers and AttributeModifier, something like:

<select wicket:id="select">
    <wicket:container wicket:id="repeatingView">
        <optgroup wicket:id="optGroup">
          <wicket:container wicket:id="selectOptions">
            <option wicket:id="option"></option>
          </wicket:container>
        </optgroup>
    </wicket:container>
</select>

In Java code, "select" is a Select; "repeatingView" is a RepeatingView. Nested inside the RepeatingView there's a WebMarkupContainer named by .newChildId(). Nested inside is another WebMarkupContainer that represents "optGroup". Inside this second WMC are an AttributeModifier that adds a dynamic label to the optgroup, and a SelectOptions that processes "selectOptions" and "option". Something like:

Select select = new Select("select");
add(select);

RepeatingView rv = new RepeatingView("repeatingView");
select.add(rv);

for(String groupName : groupNames){

    WebMarkupContainer overOptGroup = new WebMarkupContainer(rv.newChildId());
    rv.add(overGroup);

    WebMarkupContainer optGroup = new WebMarkupContainer("optGroup");
    overOptGroup.add(optGroup);
    optGroup.add(
        new AttributeModifier("label",true,new Model<String>(groupName))
    );
    optGroup.add(
        new SelectOptions<MyBean>(
            "selectOptions",listOfBeanOptionsForThisGroup,new MyBeanRenderer()
        )
    );
}

(this is supposing Strings are passed directly as group names and that the options refer to beans of type MyBean, listed in the variable listOfBeanOptionsForThisGroup)

I suppose it shouldn't be hard to refactor this solution into something that uses much less nesting, if anyone's got suggestions, I'll edit them into the answer and credit them. Using ListView instead of RepeatingView should also reduce code size.

Ok, so at the moment my solution is to have something like this:

   interface Thing {
       String getCategory();
   }

and then:

            List<Thing> thingList = service.getThings();
    DropDownChoice<Thing> dropDownChoice = new DropDownChoice<Thing>("select",
            thingList) {
        private static final long serialVersionUID = 1L;
        private Thing last;

        private boolean isLast(int index) {
            return index - 1 == getChoices().size();
        }

        private boolean isFirst(int index) {
            return index == 0;
        }

        private boolean isNewGroup(Thing current) {
            return last == null
                    || !current.getCategory().equals(last.getCategory());
        }

        private String getGroupLabel(Thing current) {
            return current.getCategory();
        }

        @Override
        protected void appendOptionHtml(AppendingStringBuffer buffer,
                Thing choice, int index, String selected) {
            if (isNewGroup(choice)) {
                if (!isFirst(index)) {
                    buffer.append("</optgroup>");
                }
                buffer.append("<optgroup label='");
                buffer.append(Strings.escapeMarkup(getGroupLabel(choice)));
                buffer.append("'>");
            }
            super.appendOptionHtml(buffer, choice, index, selected);
            if (isLast(index)) {
                buffer.append("</optgroup>");
            }
            last = choice;

        }
    };

This requires that thingList is already sorted based on the category.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!