|
Multifield validation
In the preceding subsection, I showed you how to perform Ajax validation on a single field. Sometimes, though, you need to validate multiple fields at the same time. For example, Figure 8 shows the places application validating the name and password fields together:
Figure 8. Validating multiple fields
Validating multiple fields
I validate the name and password fields together when the user submits the form, so I don't need Ajax for this example. Instead I will use JSF 2's new event system, as shown in Listing 11:
Listing 11. Using <f:event>
<h:form id="form" prependId="false">
<f:event type="postValidate"
listener="#{cc.attrs.managedBean.validate}"/>
...
</h:form>
<div class="error" style="padding-top:10px;">
<h:messages layout="table"/>
</div>
In Listing 11, I use <f:event>, which — like <f:ajax> — is new for JSF 2. The <f:event> tag is similar to <f:ajax> in another respect, too: it's simple to use.
You put an <f:event> tag inside a component tag, and when the specified event (specified with the type attribute) occurs to that component, JSF invokes a method, specified with the listener attribute. So, in English, what the <f:event> tag in Listing 11 means is: After validating the form, invoke the validate() method on the managed bean that the user passed to this composite component. That method is shown in Listing 12:
Listing 12. The validate() method
package com.clarity
import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent
import javax.faces.component.UIInput
@ManagedBean()
@SessionScoped
public class User {
private final String VALID_NAME = "Hiro";
private final String VALID_PASSWORD = "jsf";
...
public void validate(ComponentSystemEvent e) {
UIForm form = e.getComponent()
UIInput nameInput = form.findComponent("name")
UIInput pwdInput = form.findComponent("password")
if ( ! (nameInput.getValue().equals(VALID_NAME) &&
pwdInput.getValue().equals(VALID_PASSWORD))) {
FacesContext fc = FacesContext.getCurrentInstance()
fc.addMessage(form.getClientId(),
new FacesMessage("Name and password are invalid. Please try again."))
fc.renderResponse()
}
}
...
}
JSF passes the validate() method in Listing 12 a component system event, from which the method obtains a reference to the component the event applies to — the login form. From the form, I use the findComponent() method to get the name and password components. If those components' values are not Hiro and jsf, respectively, I store a message on the faces context and tell JSF to proceed immediately to the life cycle's Render Response phase. This way, I avoid the Update Model Values phase, which would push the bad name and password through to the model (see Figure 5).
You may have noticed that the validation methods in Listing 10 and Listing 12 are written in Groovy. Unlike Listing 4, where the only advantage to using Groovy was freedom from semicolons and return statements, the Groovy code in Listing 10 and Listing 12 frees me from casting. For example, in Listing 10, ComponentSystemEvent.getComponent() and UIComponent.findComponent() both return type UIComponent. With the Java language, I would have to cast the return values of those methods. Groovy does the casting for me. |
|