In my JSF/Facelets app, here's a simplified version of part of my form:
<h:form id="myform"> <h:inputSecret value="#{createNewPassword.newPassword1}" id="newPassword1" /> <h:message class="error" for="newPassword1" /> <h:inputSecret value="#{createNewPassword.newPassword2}" id="newPassword2" /> <h:message class="error" for="newPassword2" /> <h:commandButton value="Continue" action="#{createNewPassword.continueButton}" /> </h:form>
I'd like to be able to assign an error to a specific h:message tag based on something happening in the continueButton() method. Different errors need to be displayed for newPassword and newPassword2. A validator won't really work, because the method that will deliver results (from the DB) is run in the continueButton() method, and is too expensive to run twice.
I can't use the h:messages tag because the page has multiple places that I need to display different error messages. When I tried this, the page displayed duplicates of every message.
I tried this as a best guess, but no luck:
public Navigation continueButton() { ... expensiveMethod(); if(...) { FacesContext.getCurrentInstance().addMessage("newPassword", new FacesMessage("Error: Your password is NOT strong enough.")); } }
What am I missing? Any help would be appreciated!
FacesContext.addMessage(String, FacesMessage) requires the component's clientId, not it's id. If you're wondering why, think about having a control as a child of a dataTable, stamping out different values with the same control for each row - it would be possible to have a different message printed for each row. The id is always the same; the clientId is unique per row.
So "myform:mybutton" is the correct value, but hard-coding this is ill-advised. A lookup would create less coupling between the view and the business logic and would be an approach that works in more restrictive environments like portlets.
<f:view> <h:form> <h:commandButton id="mybutton" value="click" binding="#{showMessageAction.mybutton}" action="#{showMessageAction.validatePassword}" /> <h:message for="mybutton" /> </h:form> </f:view>
Managed bean logic:
/** Must be request scope for binding */ public class ShowMessageAction { private UIComponent mybutton; private boolean isOK = false; public String validatePassword() { if (isOK) { return "ok"; } else { // invalid FacesMessage message = new FacesMessage("Invalid password length"); FacesContext context = FacesContext.getCurrentInstance(); context.addMessage(mybutton.getClientId(context), message); } return null; } public void setMybutton(UIComponent mybutton) { this.mybutton = mybutton; } public UIComponent getMybutton() { return mybutton; } }
In case anyone was curious, I was able to figure this out based on all of your responses combined!
This is in the Facelet:
<h:form id="myform"> <h:inputSecret value="#{createNewPassword.newPassword1}" id="newPassword1" /> <h:message class="error" for="newPassword1" id="newPassword1Error" /> <h:inputSecret value="#{createNewPassword.newPassword2}" id="newPassword2" /> <h:message class="error" for="newPassword2" id="newPassword2Error" /> <h:commandButton value="Continue" action="#{createNewPassword.continueButton}" /> </h:form>
This is in the continueButton() method:
FacesContext.getCurrentInstance().addMessage("myForm:newPassword1", new FacesMessage(PASSWORDS_DONT_MATCH, PASSWORDS_DONT_MATCH));
And it works! Thanks for the help!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With