1

To support our organization's component library, I would like to create an enhanced selectManyMenu. A requirement is that it resemble the type that features a dropdown menu, whose menu items have checkboxes showing whether they are selected. On top of this, I would like the the top row of the drop down, the area that is always visible to show 'bubbles' for lack of a better term, containing the label of the selected item as well as an 'X' button to remove each one, similar to a 'tag' widget.

I would like to create a JSF custom component, rather than decorating the existing <h:selectManyMenu> with some jQuery plugin that hides it and renders its own widget with a bunch of obfuscated javascript that I have no idea how it works. To be honest, none of the ones I've found fit in very well with our UI, and fundamentally I don't feel as though that is good use of JSF, to slop in some jQuery widget when JSF has such robust custom component features.

To get to my current problem, I have a custom component class set up that extends UIInput and provides the encode*() methods to render a <select> with its <option> tags same as an <h:selectManyMenu> does. I'm having a problem with the decode() method:

@Override
public void decode(FacesContext context) {
    Map<String, String> requestParams = context.getExternalContext().getRequestParameterMap();
    String clientId = getClientId();
    Object param = requestParams.get(clientId);
    LOG.debug("param: {}", param);
}

The issue is param ends up being a single string no matter how many items I select. I have verified on the front end the exact same POST request is sent when I use <h:selectManyMenu>, so I am guessing I have to do something different in decode() to all of the values from the request.

For bonus points, can anyone point me to some concise explanation of the source code for, say, even just <h:inputText>. I am able to browse the source for the JSF implementation we are using, Mojarra, but it gets extremely hard to follow since it uses separate renderers, and all sorts of factories and things to select which renderer to use, etc. I have gotten by so far by leaning on composite components, with backing components when necessary, but this one and a few others coming down the pipe I think are beyond what composite components can be used effectively for.

Also, is this the best approach to accomplish what I'm after? Would I be better off creating a custom renderer for the existing <h:selectManyMenu>? That seems like an even more elegant solution since this component basically IS a selectManyMenu just rendered a little differently and having a bit of javascript on the front end.

Matt
  • 823
  • 1
  • 8
  • 17

1 Answers1

1

I gather your question boils down to:

How can I obtain a request parameter with multiple values in JSF?

The answer is: use ExternalContext#getRequestParameterValuesMap().

@Override
public void decode(FacesContext context) {
    Map<String, String[]> requestParamValues = context.getExternalContext().getRequestParameterValuesMap();
    String clientId = getClientId(context);
    String[] params = requestParamValues.get(clientId);
    // ...
}

but it gets extremely hard to follow since it uses separate renderers, and all sorts of factories and things to select which renderer to use, etc

Not sure, but perhaps you're looking for What is the relationship between component family, component type and renderer type? or How do I determine the renderer of a built-in component.

Would I be better off creating a custom renderer for the existing <h:selectManyMenu>? That seems like an even more elegant solution since this component basically IS a selectManyMenu just rendered a little differently and having a bit of javascript on the front end.

Makes indeed more sense.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks BalusC, those two links contained much information I was missing. I also found http://omnifaces-fans.blogspot.ro/2014/11/omnifaces-component-family-component.html to be very helpful in organizing my component library. – Matt Aug 21 '15 at 12:10