wicketstuff/core

Select2 List of Lists

cdjost opened this issue · 13 comments

Hi,

I am trying to create a select2 of a List<List>. Because the states that I am trying to represent contains multiple entries. The ChoiceProvider has the generic <List>. The getIdValue Method that I need to override expects a List as the parameter. But the parameter provided by the AbstractSelect2Choice class has just the type TYPE. To be it seems like the component is completely flatining my maps. Is that behavior expected or is it a bug?

Greetings

Caused by: java.lang.ClassCastException: class de.XXX.State cannot be cast to class java.util.List (de.XXX.State is in unnamed module of loader 'deployment.XXX-ear-development-work.ear' @7ab7edfd; java.util.List is in module java.base of loader 'bootstrap') at deployment.pritt-ear-development-work.ear.pritt-web.war//de.XXX.common.RequestStateS2Provider.getIdValue(RequestStateS2Provider.java:17) at deployment.pritt-ear-development-work.ear.pritt-web.war//org.wicketstuff.select2.AbstractSelect2Choice.addOption(AbstractSelect2Choice.java:402) at deployment.pritt-ear-development-work.ear.pritt-web.war//org.wicketstuff.select2.AbstractSelect2Choice.onComponentTagBody(AbstractSelect2Choice.java:443) at deployment.pritt-ear-development-work.ear.pritt-web.war//org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy.onComponentTagBody(DefaultMarkupSourcingStrategy.java:70) at deployment.pritt-ear-development-work.ear.pritt-web.war//org.apache.wicket.Component.internalRenderComponent(Component.java:2491)

I can't check it at the moment, but I doubt that your list of list is unpacked by select2.

Quickstart or refence to your code here on GitHub?

The code is not hosted. I will give you a quick start.

This is the method that creates the select2:

public static void addStatusSelect2(final String wicketId, IModel<List<ERequestState>> requestStateModel,
      final List<List<ERequestState>> possibleStates,
      final FilterForm filterForm) {
    Select2Choice<List<ERequestState>> statusSelect = new Select2Choice<>(wicketId, requestStateModel, new RequestStateS2Provider(possibleStates));
    statusSelect.getSettings().setCloseOnSelect(true);
    filterForm.queue(statusSelect);
  }

Thats my choice provider:

public class RequestStateS2Provider extends ChoiceProvider<List<ERequestState>> {


  private final List<List<ERequestState>> selectableStates;
  private List<List<ERequestState>> currentStates;

  public RequestStateS2Provider(List<List<ERequestState>> selectableStates) {
    this.selectableStates = selectableStates;
  }

  @Override
  public String getDisplayValue(List<ERequestState> listOfStates) {
    // just i18n handling
  }

  @Override
  public String getIdValue(List<ERequestState> listOfStates) {
    return String.valueOf(selectableStates.indexOf(listOfStates));
  }

  @Override
  public void query(String term, int page, Response<List<ERequestState>> response) {
   //...
    response.addAll(currentStates);
  }

  @Override
  public Collection<List<ERequestState>> toChoices(Collection<String> collection) {
    //...
  }
}

I get the error message postet above directly after I call a page that contains this component

Sorry, from that code snippet I cannot identify the problem.

Please attach a proper https://wicket.apache.org/start/quickstart.html

Thanks and sorry :(

You're right, AbstractSelect2Choice#onComponentTagBody() flattens your list:

This code should only be triggered when using a Select2MultiChoice, where the selection is a list.
But your list-of-list triggers it too unfortunately.

No worries :)
I have not really looked at the wicketstuff code base, but I would like to try and fix that. Is that ok?

Sure PRs are always welcome :)

It seems like a small instanceof check was all thats needed. Manual testing seems to work. But I have a problem with the unit-test. I can not get the test for a value change (testSelect2ChoiceLOLsChangeValue) to run. I have no experience with the WicketTester. Would someone be willing to take a look at the test? https://github.com/cdjost/core

You have to use POST parameters, otherwise the form component will not accept your input:

wicketTester.getRequest().getPostParameters().setParameterValue("selectState", "2");

Instead of that instanceof I'd prefer that we separate that method in the respective subclasses:

AbstractSelect2Choice

@Override
public void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag)
{
	if (provider == null) {
 		super.onComponentTagBody(markupStream, openTag);
 	} else {
 		M currentValue = getCurrentValue();
 		replaceComponentTagBody(markupStream, openTag, createOptions(currentValue));
	}
}

Select2Choice

@Override
protected CharSequence createOptions(T currentValue)
{
	final AppendingStringBuffer buffer = new AppendingStringBuffer();

	if (currentValue != null) {
		addOption(currentValue, buffer);
	}
		
	return buffer;
}

Select2MultiChoice

@Override
protected CharSequence createOptions(Collection<T> currentValues)
{
	final AppendingStringBuffer buffer = new AppendingStringBuffer();

	for (T value : currentValues) {
		addOption(value, buffer);
	}
		
	return buffer;
}

This removes some ugly casts and @SupressWarnings too.

You are right, that is much cleaner. Thank you! I created a pull request. On more question, in our project we use wicketstuff 8.6.0, will this be also available there?

You are right, that is much cleaner. Thank you! I created a pull request. On more question, in our project we use wicketstuff 8.6.0, will this be also available there?

I've pushed the change to 8.x too. Thanks!

Hi, one last question: at what point will the change be published to the maven repos?

A new release of Wicketstuff Core is usually made after a release of Apache Wicket.
There was a discussion recently at dev@wicket.apache.org to cut new releases of 7.x, 8.x and 9.x.
I guess it will be soon.