Flash messages in transient and cached pages - jsf

i have a simple contact form with an underlying transient view.
<f:view transient="true">
<h:panelGroup id="messages" layout="block" >
<o:messages escape="false" infoClass="info" errorClass="error" globalOnly="true" rendered="#{not empty facesContext.messageList}" />
</h:panelGroup>
<h:form id="contactform">
please enter your name:
<h:inputText id="name" required="true" requiredMessage="#{msg.fieldrequired}">
...
</h:form>
</f:view>
this page is also cached (using omnifaces CacheControlFilter), since the content here is not really dynamic and the user only submits some request parameters. when the form has been submitted sucessfully, the managedbean adds a flash message and performs a refresh:
public void showSuccess() throws IOException {
Messages.addFlashGlobalInfo("submit_success");
Faces.refresh(); //ensure cleaning all input fields in the form
}
after that, the page now contains the div with the rendered faces message and this message is now present every time the user performs a GET to this page again.
<div id="messages">
<ul>
<li>Thank you for your feedback</li>
</ul>
</div>
is there a way to get rid of the message?
thanks in advance.

Related

h:selectBooleanCheckbox always pass false to validator

I have h:selectBooleanCheckbox but it passes 'false' to the validator. always.
<h:panelGroup id="tncPanel">
<label>
<h:selectBooleanCheckbox id="tncSelection" value="#{businessBean.tncSelection}">
<f:validator validatorId="checkboxValidator"/>
<f:attribute name="label" value="Please agree terms and conditions."/>
</h:selectBooleanCheckbox>
I have read and agreed to all the
<a href="#" data-toggle="modal" data-target="#modal-term-and-conditions">
Terms and Conditions.
</a>
</label>
</h:panelGroup>
<h:panelGroup id="buttonPanel">
<h:commandLink id="nextButton" action="#{businessBean.goNext}">
Submit
</h:commandLink>
</h:panelGroup>
Why I have panelGroup here is, based on logic in top of page, I have a logic to display/not the button and checkbox
This is my Validator.
#FacesValidator("checkboxValidator")
public class CheckboxValidator implements Validator {
private static final String DEFAULT_LABEL = "Please confirm the address.";
#Override
public void validate(FacesContext context, UIComponent component, Object value){
String checkBoxValue = String.valueOf(((HtmlSelectBooleanCheckbox) component).getSubmittedValue());
System.out.println("checkBoxValue " + checkBoxValue);
System.out.println("value2: " + value);
String label = String.valueOf(component.getAttributes().get("label"));
if ("null".equals(label)) {
label = DEFAULT_LABEL;
}
if("false".equalsIgnoreCase(checkBoxValue)){
FacesMessage msg = new FacesMessage(null, label);
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
}
}
Validator sysout always prints checkBoxValue false
UPDATE
After comment on Balusc, I add another sysout to print directly the parameter value. But still it's printing as value2: false.
There is a bug related to this situation , When you render a container that holds a from from another form you the rendered form loses its view state ,Thus form is submitted to no destination solution is to render the form container and the form its self from the other form
For example that won't work :
<h:panelGroup id="panel">
<h:form>
<h:commandButton value="Submit" rendered="#{not testAction.flag}">
<f:ajax render=":panel" listener="#{testAction.submit()}"/>
</h:commandButton>
</h:form>
<h:panelGroup id="panel">
<h:form id="secondForm" rendered="#{testAction.flag}">
<h:selectBooleanCheckbox id="checkBox" value="#{testAction.boolVal}">
<f:validator validatorId="checkboxValidator"/>
</h:selectBooleanCheckbox>
<h:commandButton value="Go" action="#{testAction.go()}"/>
</h:form>
</h:panelGroup>
Second form submit will be like this :
secondForm won't have its view state the form is submitted but with no destination on the server cuz the view object is not fetched on the server that requires the javax.faces.ViewState value to be fetched by what you have to do here is to render form as well in the f:ajax:
<f:ajax render=":panel :secondForm" listener="#{testAction.submit()}"/>
That inform server to backup the second form rendered with the javax.faces.ViewState
Refer to that post : Rendering other form by ajax causes its view state to be lost, how do I add this back? for more info
Hope that was the problem :)

Messages not working inside Primefaces TabView

I have a custom tag called "fieldWrapper" to bind labels with their respective inputs and provide validation messages.
The code of the component:
<h:panelGroup id="#{for}CompleteFieldContainer"
styleClass="completeFieldContainer"
layout="block"
rendered="#{rendered}">
<h:panelGroup id="#{for}FieldWithLabelContainer" layout="block"
styleClass="fieldWithLabelContainer #{fieldWrapperBean.getRequiredClass(required)} #{totalSizeClass}">
<c:if test="#{!empty check and check}">
<div class="labelContainer #{labelSizeClass} checkInput">
<ui:insert />
</div>
<div class="labelContainer #{for}LabelContainer checkStyle">
<h:outputLabel for="#{for}" value="#{label}" title="#{title}"/>
</div>
</c:if>
<c:if test="#{empty check or not check}">
<div class="labelContainer #{labelSizeClass} #{for}LabelContainer #{checkStyle}">
<h:outputLabel for="#{for}" value="#{label}" title="#{title}"/>
</div>
<ui:insert />
</c:if>
</h:panelGroup>
<h:panelGroup rendered="#{renderError}" layout="block" styleClass="messageContainer">
<p:message for="#{for}" id="#{for}Message" rendered="true"/>
</h:panelGroup>
</h:panelGroup>
One example of this tag is the following:
<gitags:fieldWrapper for="codeInput"
label="#{msg.code}"
labelSizeClass="size75"
totalSizeClass="size175"
required="false">
<p:inputText id="codeInput"
value="#{clienteFinderManager.codigo}"
styleClass="inputText size100"/>
</gitags:fieldWrapper>
It automatically adds a message for that input, that is rendered when bean validation triggers.
It's working perfectly inside all components except p:tabView.
When I use it inside a tabView messages are queued but not written, but, if i add manually messages after the component they are written:
<gitags:fieldWrapper for="codeInput"
label="#{msg.code}"
labelSizeClass="size75"
totalSizeClass="size175"
required="false">
<p:inputText id="codeInput"
value="#{clienteFinderManager.codigo}"
styleClass="inputText size100"/>
<p:message for="codeInput" id="codeInputMessage" rendered="true"/>
</gitags:fieldWrapper>
Bean Validation Inside Tabs
Any idea of why is this happening?
It was a bug: https://code.google.com/p/primefaces/issues/detail?id=5238
Fixed in primefaces 5.0.
I have a fix in any primeface version.
You need to take <p:outputLabel> instead of <p:message>.
Take one string variable message and set error message in to that . Keep <p:ajax> inside<p: tabView> on tabChange event call the action method from bean and empty the error message. Because we need every time while changing the tab the error message should clear. After click on the submit button then only the error message will show.
If any clarification contact me.

PrimeFaces - can't rendered

I have a little problem with the rendered attribute. I want to use it for login, if someone connects for the first time on my website, he can log in, but when he's logged, he can't see the form. But when the page is loaded, I can't hide the form...
Maybe it would be easier with my code.
HTML
<h:panelGroup id="sidebar" layout="block">
<h:panelGroup id="sbox1" layout="block">
<h:panelGroup class="title" layout="block">
<h2> Espace Membre </h2>
</h:panelGroup>
<ul class="style2">
<h:form rendered="#{!membreCtrl.estConnecte}">
Connection : <h:outputText value="#{membreCtrl.estConnecte}"></h:outputText>
Login : <h:inputText id="login" value="#{membreCtrl.login}" /> <br/>
Password : <h:inputSecret id="mdp" value="#{membreCtrl.mdp}" /> <br/>
<h:commandButton action="#{membreCtrl.identifier()}" value="Se connecter" />
</h:form>
</ul>
</h:panelGroup>
Bean
public String identifier() {
membreConnecte = membreEJB.connecter(login, mdp);
if (membreConnecte == null) {
return "FAILURE";
}
estConnecte = true;
return "SUCCESS";
}
If I put the right login/password, I get on the index page, but then I would like to hide the <h:form ..that I wrote.
But it doesn't work. When I print the result in the Bean, my boolean "estConnecte" is true, but not when I write it on the HTML code.
Did you update the form after the button's click?
Put a p:outputPanel inside the form, if you are using Primefaces, and then update the form:
<h:form>
<p:outputPanel rendered="#{!membreCtrl.estConnecte}">
Connection : <h:outputText value="#{membreCtrl.estConnecte}"></h:outputText>
Login : <h:inputText id="login" value="#{membreCtrl.login}" /> <br/>
Password : <h:inputSecret id="mdp" value="#{membreCtrl.mdp}" /> <br/>
<p:commandButton action="#{membreCtrl.identifier()}" value="Se connecter" update="#form"/>
<p:outputPanel/>
</h:form>

Scrolling to anchor or page bottom after JSF form validation fail

I have a contact form at the bottom of a page with required and validated form fields. If validation fails, how can I get the scroll position back to the bottom of the page?
I want this page to work with Javascript disabled, so no AJAX solutions. I have something like this:
<a id="contact"></a>
<h:form id="cform">
<h5>Contact!</h5>
<h:outputLabel for="name">Name:
<h:message id="nameMsg" for="name" />
</h:outputLabel>
<h:inputText id="name" value="#{bean.name}" required="true" requiredMessage="Please enter name!" />
<h:outputLabel for="email">Email:
<h:message id="emailMsg" for="email" />
</h:outputLabel>
<h:inputText id="email" value="#{bean.email}" required="true" requiredMessage="Email is required!">
<f:validator validatorId="myValidator" />
</h:inputText>
<h:outputLabel for="comment">Comment:
<h:message id="commentMsg" for="comment" />
</h:outputLabel>
<h:inputTextarea id="comment" value="#{bean.comment}" required="true" requiredMessage="Please enter a comment!"/>
<h:commandButton action="#{bean.go}" id="send" value="send" />
</h:form>
I thought about doing validations on the bean side and doing manual redirects to the appropriate anchor, but that seems to defeat the purpose of using JSF to begin with. I assume there is an easy way to do this, but I'm having trouble Googling a solution because I'm probably not wording the question right. Any one?
You can use <f:event type="postValidate"> to have a listener hook right after the validations phase. You can use FacesContext#isValidationFailed() to check if validation has failed or not. You can use Flash#setKeepMessages() to let the faces messages survive a redirect (they're namely by default request scoped!). You can use ExternalContext#redirect() to perform a redirect in a non-action method.
So, summarized, this should do:
<h:form id="cform">
...
<f:event type="postValidate" listener="#{bean.postValidate}" />
</h:form>
with:
public void postValidate() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.isValidationFailed()) {
context.getExternalContext().getFlash().setKeepMessages(true);
context.getExternalContext().redirect("contact.xhtml#cform");
}
}
Or we can use f:ajax onerror= for do something if they are an errors :
<p:commandButton **>
<f:ajax onerror="window.scrollTo(0, 0);" />
</p:commandButton>
You don't need an explicit anchor tag for this, the id of the form will do.
You could make Faces render the id at the end of the form action Url.
Eg.
... Your main page content goes here ....
<form id="contact-form" action="/MyView.jsf#contact-form" method="post">
This will cause the browser to scroll to the form after it is submitted.
It shows in the Url too.
You could probably implement a custom Form renderer to do this.

Rendering a component outside the form's scope in JSF2

I am creating a simple page that will, after clicking a button, replace one panelGroup with another. First, the code:
<h:body>
<ui:composition template="/elements/templateWithMenu.xhtml">
<ui:define name="content">
<div class="rightContent">
<h:panelGroup id="lol" rendered="#{test.firstStep.booleanValue()}">
<h3>This should disappear</h3>
<h:form id="newPollForm1" rendered="#{test.firstStep.booleanValue()}">
<fieldset>
<h:commandLink value="Next" action="#{test.firstStepCompleted()}" >
<f:ajax execute="#all" render="lol" />
</h:commandLink>
</fieldset>
</h:form>
</h:panelGroup>
<h:panelGroup rendered="#{test.secondStep.booleanValue()}">
Works!
</h:panelGroup>
</div>
</ui:define>
</ui:composition>
</h:body>
The backing bean simply sets the firstStep as false, and secondStep as true.
Now, when I tried running this, I got <f:ajax> contains an unknown id 'lol' - cannot locate it in the context of the component j_idt39. After googling a bit, I found out that for elements outside the form's scope, I need to use SEPARATOR_CHAR (:). That didn't work. So I tried messing with different combinations of #{component} and #{cc}, but nothing works. I even found this awesome explanation, but again, I failed miserably. If I use #all, everything goes ok (one panel is replaced with another), but I really need to render a specific component.
Help? Please?
You need to update the common parent <div class="rightContent"> instead. This one is always rendered and thus guarantees that JavaScript/Ajax can access and mainpulate its children. Replace it by <h:panelGroup layout="block"> and give it an id.
<h:panelGroup layout="block" id="content" class="rightContent">
<h:panelGroup rendered="#{test.firstStep}">
<h3>This should disappear</h3>
<h:form id="newPollForm1">
<fieldset>
<h:commandLink value="Next" action="#{test.firstStepCompleted()}" >
<f:ajax execute="#form" render=":content" />
</h:commandLink>
</fieldset>
</h:form>
</h:panelGroup>
<h:panelGroup rendered="#{test.secondStep}">
Works!
</h:panelGroup>
</h:panelGroup>
Using this Test.java class:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class Test {
private int number = 0;
public void firstStepCompleted() {
number++;
}
public boolean isFirstStep() {
return number == 0;
}
public boolean isSecondStep() {
return number == 1;
}
}
Note that I removed the superfluous Boolean#booleanValue() calls and the duplicated rendered contition on the form.
If that still doesn't work, then the /elements/templateWithMenu.xhtml apparently contains another naming container component which has prepended its ID. For starters who haven't memorized all naming container components yet, an easy way to figure the real right client ID is to open the page in browser, rightclick and View Source and then locate the JSF-generated HTML element and take exactly its id attribute value (and prefix it with : in the <f:ajax render>).

Resources