Search code examples
jsfprimefaces

PrimeFaces SelectOneMenu with icons (custom f:selectItems)


I am trying to display all available FontAwesome icons in a p:selectOneMenu component.

The renderer is supposed to render the icon first, then display the icon's name. A similar example can be found here but is implemented especially for BootStrap: https://mjolnic.com/fontawesome-iconpicker/

 ----------------------------------
|- ICON - | Icon name              |
 ----------------------------------

Unfortunately, the custom columns just do not get rendered. The p:selectOneMenuappears but is rendered as by default.

My picker xhtml page looks as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.org/ui"> 

<h:head></h:head> 
<body>
    <p:panel>
        <h:form id="iconPicker">
            <p:selectOneMenu id="iconSelectOneMenu"
            value="#{iconController.availableIconStrings}">
                <f:selectItem itemLabel="Choose icon"
                noSelectionOption="true" />
                <f:selectItems
                value="#{categoryController.availableIconStrings}"
                var="_icon" itemValue="#{_icon}"
                itemLabel="#{_icon}" />
                <p:column>
                    <p:button id="iconButton" icon="#{_icon}" />
                </p:column>
                <p:column>
                    <h:outputText value="#{_icon}" />
                </p:column>
            </p:selectOneMenu>
        </h:form>
    </p:panel>
</body> 
</html>

The IconController class:

public class IconController implements Serializable {

    private List<String> availableIconStrings;

    public IconController() { }

    @PostConstruct
    public void init() {
        availableIconStrings = new ArrayList<>();
        availableIconStrings.addAll(Arrays
                .asList("fa-adjust,fa-adn,fa-align-center,fa-align-justify,fa-align-left,"
                        + "fa-align-right,fa-ambulance,fa-anchor,fa-android,fa-angellist,"
                        + "fa-angle-double-down,fa-angle-double-left,fa-angle-double-right,"
                        + "fa-angle-double-up,fa-angle-down,fa-angle-left,fa-angle-right"
                        // Shortened list
                        .split(",")));
    }

    public List<String> getAvailableIconStrings() {
        return availableIconStrings;
    }

    public void setAvailableIconStrings(List<String> availableIconStrings) {
        this.availableIconStrings = availableIconStrings;
    }
}

As you can see, I am trying to render the icon using a p:button. Do I understand it correctly that I need a PrimeFaces component that is able to display icons (e.g. p:button, p:commandButton, p:commandLink) to achieve my goal?

Any help is appreciated. Thanks a lot.

P.S.: Using PrimeFaces 5.3, JSF 2.2 and Mojarra on WildFly 9.0.2


Solution

  • Two things:

    In order to use p:column in combination with p:selectOneMenu you need to declare the var attribute on the p:selectOneMenu and reference it within your p:column. An example can be found on the PrimeFaces showcase.

    So your code should be:

    <p:selectOneMenu id="iconSelectOneMenu"
            value="#{iconController.availableIconStrings}" var="ic">
                <f:selectItem itemLabel="Choose icon"
                noSelectionOption="true" />
                <f:selectItems
                value="#{categoryController.availableIconStrings}"
                var="_icon" itemValue="#{_icon}"
                itemLabel="#{_icon}" />
    
                <p:column>
                    <p:button id="iconButton" icon="#{ic}" />
                </p:column>
                <p:column>
                    <h:outputText value="#{ic}" />
                </p:column>
            </p:selectOneMenu>
    

    Now, You are facing a bug because you are using a List<String> as explained on this SO question:

    So, if the item value is an instance of String, custom content via p:column is totally ignored.

    You can find a workaround in the same post: https://stackoverflow.com/a/32740430/2118909