Danilo Piazzalunga
Danilo Piazzalunga

Reputation: 7844

Mutually exclusive input fields with JSF and PrimeFaces

I have a PrimeFaces application where I would like to make two input text fields mutually exclusive: the user should fill either field, but not both.

In the following example, the user could search contacts either by phone number or by email.

<h:form>
    <h:outputLabel>Phone Number:
        <h:inputText id="phoneInput" value="#{contactSearch.phone}"
                     disabled="#{not empty contactSearch.email}">
            <p:ajax event="keyup" update="emailInput"/>
        </h:inputText>
    </h:outputLabel>
    <h:outputLabel>Email Address:
        <h:inputText id="emailInput" value="#{contactSearch.email}"
                     disabled="#{not empty contactSearch.phone}">
            <p:ajax event="keyup" update="phoneInput"/>
        </h:inputText>
    </h:outputLabel>

    <!-- Possibly other fields... -->

    <h:commandButton value="Search" action="#{contactSearch.search}"/>
</h:form>

Is this the proper way to do it? I am concerned about:

Upvotes: 0

Views: 660

Answers (1)

BalusC
BalusC

Reputation: 1109570

This is not trivial in standard JSF. JSF utility library OmniFaces has a validator for exactly this purpose, the <o:validateOne>.

<h:inputText id="email" ... />
<h:inputText id="phone" ... />
<o:validateOne components="email phone" />

However, in UX perspective, you'd better redesign your form to provide a single UISelectOne component to select the type and a single UIInput field to enter the value. E.g.

<h:selectOneRadio ... value="#{bean.type}">
    <f:selectItem itemValue="email" />
    <f:selectItem itemValue="phone" />
</h:selectOneRadio>
<h:inputText ... value="#{bean.value}" />

Update: as server side validation is not affordable and you'd really like to disable the the other without making much ajax traffic, your only bet is using pure JavaScript/jQuery for the job (if necessary in combination with server side validation as fallback).

Here's a generic jQuery based approach:

<h:inputText styleClass="onlyone" a:data-onlyone="groupName" />
<h:inputText styleClass="onlyone" a:data-onlyone="groupName" />
...

$(document).on("input", ":input.onlyone", function() {
    var $this = $(this);
    var $others = $("[data-onlyone='" + $this.data("onlyone") + "']").not($this);
    $others.val(null).attr("disabled", !!$this.val());
});

The data-onlyone value should represent the group name, so you can have multiple of "only one" inputs throughout the document.

Upvotes: 3

Related Questions