4
votes

I'm developing a JSF web application where I need to use periodicities as data structure. Here there are the Java classes I work with:

public class Periodicity implements Serializable {

    private Integer value = 0;

    private PeriodicityType type;

    //Getter and setters

}

public enum PeriodicityType {
    DAY, WEEK, MONTH, YEAR
}

That way I can specify different periodicities for my tasks, which can combine values with PeriodicityType.

I also have created an input composite element called periodicityInput.xhtml, which I can use to provide that data type in different forms in a reusable way:

<!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:composite="http://java.sun.com/jsf/composite"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:body>
    <composite:interface>
        <composite:attribute name="value" required="true" />
        <composite:attribute name="disabled" required="false" default="false" />
    </composite:interface>

    <composite:implementation>
        <h:panelGrid columns="2" id="#{cc.id}">
            <p:spinner value="#{cc.attrs.value.value}" min="1"
                id="value_spinner" disabled="#{cc.attrs.disabled}" />
            <p:selectOneMenu value="#{cc.attrs.value.type}" style="width:200px"
                disabled="#{cc.attrs.disabled}">
                <f:selectItem noSelectionOption="true"
                    itemLabel="#{windowsMessages.NOT_ASSIGNED}" />
                <f:selectItems value="#{viewUtils.periodicityTypes}" />
            </p:selectOneMenu>
        </h:panelGrid>
    </composite:implementation>
</h:body>
</html>

Basically I have an spinner element and a selectOneMenu, in order to select a value and a type for the periodicity. There's also the chance not to select any type, in this case the input numeric value must be zero. Or, even better, if no periodicity selected the input must be converted into a null/null tuple.

As I read in some sites there's the chance to validate multiple JSF components at once accesing the id in the validation method:

UIInput confirmComponent = (UIInput) component.getAttributes().get("confirm");

Question is, how to adapt it in order to use in a composite component which doesn't have a fixed id?

1

1 Answers

3
votes

One way would be to create a backing component extending UIInput and do the job in UIInput#getSubmittedValue(). The child inputs are just directly available by findComponent().

<cc:interface componentType="inputPeriodicity">
    ...
</cc:interface>
<cc:implementation>
    ...
    <p:spinner id="value_spinner" ... />
    <p:selectOneMenu id="type_menu" ... />
    ...
</cc:implementation>

with

@FacesComponent("inputPeriodicity")
public class InputPeriodicity extends UIInput implements NamingContainer {

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override
    public Object getSubmittedValue() {
        UIInput typeMenu = (UIInput) findComponent("type_menu");
        String type = (String) typeMenu.getSubmittedValue();

        if (type == null || type.isEmpty()) {
            UIInput valueSpinner = (UIInput) findComponent("value_spinner");
            valueSpinner.setSubmittedValue("0"); // Don't use int/Integer here!
        }

        return super.getSubmittedValue();
    }

}

See also:


Unrelated to the concrete problem, the <h:panelGrid id="#{cc.id}"> really isn't right. Give it a fixed ID instead if you really need to.