I have a RichFaces project on JSF 2.2 and I wanted to show status updates and messages to the user while processing their request. I wanted to use a a4j:outputpanel with a simple outputext for this. I added a system.out line and it shows up on my server console when but the text on the screen is not updated.
In my process class:
private void showAdvise(final String message) {
System.out.println(">>>>>ComUI showAdvise: " + message);
this.beidCardStatusBean.updateStatus(message);
}
On my jsf page:
- I launch the proces with:
<a style="font-size:150%;" onclick="startEID();"
href="savePhoto.do?userId=#{detailUserBean.id}">#{UIMessages['button.loadPhoto']}</a>
<a:outputPanel id="eidPaneContainer" ajaxRendered="true">
<rich:popupPanel header="EID" id="eidPane" width="100" height="80">
<h:outputText id="eidStatus" value="#{beidCardStatusBean.getStatus()}" >
</h:outputText>
</rich:popupPanel>
</a:outputPanel>
In order to update the components the page has to send a request to the server, it doesn't happen automatically when something on the server changes. The easy solution is to use a poll, e.g.
<a4j:poll id="poll" interval="2000" enabled="#{bean.pollEnabled}" render="poll, popup" />
This will rerender the popup every 2 seconds. So in your case startEID needs to set pollEnabled and rerender the poll to start it.
PopupPanel might be a bit problematic when it comes to rerendering, try setting domElementAttachment="parent" if this doesn't work.
Related
Does anyone know if it's possible to update a JSF message or messages element AFTER its initial rendering via PrimeFaces' p:menuitem?
For example, I have a PrimeFaces p:menuitem I am using to open a p:dialog, and that p:dialog has a p:messages element whose message I would like to update and show the moment that the p:dialog is opened - I can't know whether there is a message I want to show or what that message should be until after the p:menuitem's action method is complete.
Unfortunately, setting the update attribute of the p:menuitem to both the id of the p:dialog and the id of the p:messages element itself does not cause the p:messages element to show its message, even though I think it should since the action method of the p:menuitem looks like it is properly adding a message to the p:messages element.
The menuitem opening the dialog:
<p:menuitem value="Show Dialog with Message" action="#{myView.prepareDialogWithMessage()}" oncomplete="PF('dialogWidget').show()" update="dialogWithMessage message" />
The dialog with the message:
<p:dialog id="dialogWithMessage" widgetVar="dialogWidget" resizable="false" dynamic="true" closable="false" showEffect="fade" hideEffect="fade">
<p:messages id="message" for="message" showDetail="true" escape="false" autoUpdate="true"/>
<div class="button-panel">
<p:commandButton value="Yes" styleClass="ui-confirmdialog-yes" action="#{myView.submitAction()}" oncomplete="PF('dialogWidget').hide();"/>
<p:commandButton value="No" styleClass="ui-confirmdialog-no" onclick="PF('dialogWidget').hide();"/>
</div>
</p:dialog>
The Java code which adds the message:
public void prepareDialogWithMessage() {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Summary of message we want to show when the dialog opens", "Details of the message we want to show when the dialog opens");
FacesContext.getCurrentInstance().addMessage("message", message);
}
Short answer: It behaves exactly as expected and implemented.
Longer answer:
Having a closer look after your edited question, I noticed the dynamic="true" on the dialog. If you read the PrimeFaces docs it states (as you already found out):
dynamic: Enables lazy loading of the content with ajax.
So when you show the dialog via javascript, its content is updated... Since this content also includes the p:messages, that is also updated. In your case updated again with the messages that are generated in the ajax call of the update of the dialog... Most likely none... So the messages you added to it in the prepareDialogWithMessage() call of the menuItem are lost.
Since you already update the dialog in the call to the menuItem, the dynamic='true' is totally superfluous and it throws a spanner in the works.
<off-topic>A suggestion is to always start creating an [mcve]. Removing more and more until the behaviour of certain parts is as expected. Removing the dynamic='true' in one of the steps would have resulted in this and you'd have known a lot more. At the same time, also try debugging more. Investigating by looking at the requests and responses in the browser developer tool. You would have seen the messages getting added to the dialog and then the dialog(contents) being totally overridden. All these things are easy too (sorry, easy instead of 'not to difficult), can/will tell you a lot and helps getting to the cause of things quicker. Either directly, or by being able to ask way more specific question that is often easier to answer</off-topic>
CommandButton displays the growl. But the previous growl message is lost. How can make growl display messages stack?
For example:
<h:form>
<p:growl id="growl" showDetail="true" life="6000" />
<p:commandButton value="Show" actionListener="#{growlView.showMessage}" update="growl" />
</h:form>
And bean function:
public void showMessage() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Hello"));
}
I click button every second. I expect that messages will store and display for 6 seconds.
But after click button, previous message hides and i see only current message.
When i debugging i have that:
FacesContext.getCurrentInstance().getMessageList().size() == 0
I tried
FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true);
than
<context-param>
<param-name>org.primefaces.messagePersistence</param-name>
<param-value>true</param-value>
</context-param>
But is doesn't work =(
Please help
An simple solution using the primefaces 5.1 for those who want to display messages on a stack manner in the same p:growl without hide the previous messages is to override the default behavior of the component adding a primefacesFixes.js file to the classpath and override the function with the commented line below:
primefacesFixes.js:
PrimeFaces.widget.Growl.prototype.show = function(b) {
var a = this;
this.jq.css("z-index", ++PrimeFaces.zindex);
//this.removeAll(); //Commenting this line prevents an ajax update tho the <p:growl> from erasing global messages
$.each(b, function(c, d) {
a.renderMessage(d);
});
};
So you call the fixes file like this on your template tag:
<h:outputScript name="javascript/primefacesFixes.js" target="head" />
And can use only one p:growl on the page to render all the needed messages.
Unfortunately, this is not currently possible. Actually, it was the default behaviour back in 2011 (having stacked growl messages) but the primefaces core team has decided to:
hide previous messages before displaying new ones on ajax update
Source: https://code.google.com/p/primefaces/issues/detail?id=1925
However, an issue was created here (October 2014) to bring back this feature but has not been reviewed yet.
Posting this on a old question, but this may be one solution (although, I'm on PFv6.2):
<p:growl id="messages" showDetail="true" keepAlive="true"/>
Simply add the keepAlive="true" to the growl element.
I'm trying to create a button that once clicked will change a property in a bean.
<h:commandButton type="button" action="#{loginBean.withdraw}" id="thousand" class="buttons" style="top:180px;left:570px;">
<f:setPropertyActionListener target="#{loginBean.withdrawAmount}" value="1000" />
</h:commandButton>
public class LoginBean {
int withdrawAmount;
This method only works when I omit the type="button" from the commandButton, but with the type="button" it doesn't work and I'm not sure why.
I need the type="button" to be there , is there any way to keep it and still make it work ?
There is an error in your facelet snippet:
There is no such attribute as class for <h:commandButton>. Possibly you meant styleClass.
As for the problem you have, you have to:
Either provide a setter method for the withdrawAmount property
public void setWithdrawAmount(int withdrawAmount) {
this.withdrawAmount = withdrawAmount;
}
and your facelet should look like:
<h:commandButton type="submit"
action="#{loginBean.withdraw}"
id="thousand"
styleClass="buttons"
style="top:180px;left:570px;">
<f:setPropertyActionListener target="#{loginBean.withdrawAmount}"
value="1000" />
</h:commandButton>
Or, you can get rid of the <f:setPropertyActionListener> and add a statement the changes the value of the withdrawAmount as a first line of the #{loginBean.withdraw} method.
In this case your facelet snippet should look like:
<h:commandButton type="submit"
action="#{loginBean.withdraw}"
id="thousand"
styleClass="buttons"
style="top:180px;left:570px;" />
and your LoginBean#withdraw() method should start with the statement, that changes the withdrawAmount value:
public String withdraw() {
this.withdrawAmount = 1000;
//the remaining logic.
}
Personally, I would prefer the first option.
More info:
< h:commandButton > tag reference
JSF Core Tag :setPropertyActionListener vs attribute vs param
The type is the entire reason why you're having this issue. I'm posting this answer because the accepted answer doesn't explain why you're experiencing the issue.
<h:commandButton/> is designed to work in 3 modes:
submit: This is the default mode that the button is set to. This mode sends an HTTP POST request to the server that triggers the JSF request processing lifecycle. It's only this mode that enables you to trigger backing bean methods(using the action or actionListener attributes).
button: This mode triggers a GET request in the application. As GET requests go, this mode is mostly suited for navigation, i.e. requesting another view or page. In this mode, there's no easy/straightforward way to execute backing bean code, or trigger the JSF request processing lifecycle. This is your current issue
reset: This mode simply resets the value of all input components within its enclosing <h:form/>
Reference:
JSF2 Command Button VDL
JSF redirect via commandButton
Difference between h:button and h:commandButton
I would appreciate it if someone can give me some hints about progress bar and ajax back-end processing.
To clarify what I need following are details:
I have a command button to do some processing at the back-end.
I would like to show a progress bar that reach the 100% when the backing bean finishes processing back-end instructions.
I looked over many threads but no luck. Most of them did not show a concrete sample how to do that.
Below is a snippet of my code:
</h:panelGrid>
<p:commandButton id="btn" value="DoSomeAction"
styleClass="ui-priority-primary" update="panel"
onclick="PF('pbAjax').start();PF('startButton1').disable();"
widgetVar="startButton1"
actionListener="#{actionBean.DoSomeAction}" />
<p:progressBar widgetVar="pbAjax" ajax="true"
value="#{progressBean.progress}" labelTemplate="{value}%"
styleClass="animated">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton2.enable()" />
</p:progressBar>
</p:panel>
This is the code for the Progress Brean:
#ManagedBean(name="progressBean")
public class ProgressBean implements Serializable {
private Integer progress;
public Integer getProgress() {
if(progress == null)
progress = 0;
else {
progress = progress + (int)(Math.random() * 35);
if(progress > 100)
progress = 100;
}
return progress;
}
public void setProgress(Integer progress) {
this.progress = progress;
}
public void onComplete() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Progress Completed", "Progress Completed"));
}
public void cancel() {
progress = null;
}
}
The result of this code is just an empty progress bar and nothing happen when I click on my button.
Thanks in advance.
It'll be easier if I simply walk you through my sample code since you have two beans and I don't know the interaction between them. You can use it to apply it to yours.
<p:commandButton>
<p:commandButton value="Start" type="button" onclick="pbAjax.start();startButton1.disable();" widgetVar="startButton1" />
Nothing impressive here. You have a commandButton with widgetVar="startButton1". When you click on it, onclick comes in and disables the commandButton. It also signals <p:progressBar> to start via pbAjax.start() (<p:progressBar> has widgetVar = "pbAjax.start()").
<p:progressBar>
<p:progressBar widgetVar="pbAjax" value="#{progressBean.progress}" ajax="true" labelTemplate="{value}%">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton1.enable()"/>
</p:progressBar>
<p:progressBar> will simply keep calling #{progressBean.progress} to update the progress. When the progress reaches 100% <p:ajax> kicks in and calls #{progressBean.onComplete}. <p:commandButton> get re-enabled and <p:growl> gets updated. Notice how I'm not using PF(...). To be honest, I'm not sure if it makes a difference, I did not test.
Note
In your <p:progressBar> you have oncomplete="startButton2.enable(). It should be startButton1.enable() since your widgetVar value for your <p:commandButton> is startButton1.
Also, notice that I did not use styleClass="animated". With this, you'll just get the bland looking blue bar. If you want to use it then you need to take some extra steps. Looking at your code, it seems you're taking it straight from the PrimeFaces showcase so I'll also use their assets.
Using styleClass="animated"
First, you're going to create a folder called resources in your webapp folder (Web Pages for Netbeans). Then create a folder called css and add in a stylesheet called style.css. The directory structure will be like this: resources/css/style.css. In style.css you're going to have to define this rule. (Don't worry if this is confusing, I'll have the whole code below).
.animated .ui-progressbar-value {
background-image: url("#{resource['images/pbar-ani.gif']}");
}
Then you're going to create an images folder under resources and place the image
pbar-ani.gif in that folder (resources/images/pbar-ani.gif). Image below.
Make sure you have <h:outputStylesheet name='css/style.css' /> in <h:head> and add styleClass="animated" in <p:progressBar>.
Important!
If you are using PrimeFaces 3.5 like I am the image will just not display (including when you're not using styleClass). If you look closely at Firebug you will see the following error
Uncaught TypeError: Object #<Object> has no method 'easeInOutCirc'
One workaround I found for this is to simply use dummy <p:dialog>.
That's it.
You can get more information about the progressBar through the developer's guide.
In case you're wondering how I knew where to get the image you'll have to download the showcase. You can read this article to find out how to download the showcase.
In my opinion, when you really want to use the showcase code, it's better if you simply download the demo. Often time I'm either not seeing the complete picture or the code in the showcase has some mistakes
Anyway here's the sample code as promised. I'm using the same ProgressBean from the showcase (same as yours). Keep in mind that you will have to come up with the logic with how your object interacts with ProgressBean to update the progress bar.
Summary
<h:head>
<h:outputStylesheet name='css/style.css' />
</h:head>
<h:body>
<h:form >
<p:growl id="growl" />
<h3>Advanced Ajax ProgressBar</h3>
<p:commandButton value="Start" type="button" onclick="pbAjax.start();
startButton1.disable();" widgetVar="startButton1" />
<br /><br />
<p:progressBar widgetVar="pbAjax" value="#{progressBean.progress}" ajax="true" labelTemplate="{value}%" styleClass="animated">
<p:ajax event="complete" listener="#{progressBean.onComplete}"
update="growl" oncomplete="startButton1.enable()"/>
</p:progressBar>
<p:dialog></p:dialog><!-- For PrimeFaces 3.5 -->
</h:form>
</h:body>
and remember your directories
resources/css/style.css
resources/images/pbar-ani.gif
I am developing a JSF application and I have many user forms where I use JSF validations.
I have an issue which annoys me, it will be easier to tell it with an example.
<h:panelGroup>
<h:selectOneRadio id="gender" value="#{registrationController.person.gender}"
required="true" requiredMessage="#{msg.commonErrorBlankField}">
<f:selectItems value="#{registrationController.genders}" />
</h:selectOneRadio>
<rich:spacer />
<rich:message for="gender" errorLabelClass="errorLabel">
<f:facet name="errorMarker">
<h:graphicImage value="#{msg.imageExclamation}" />
</f:facet>
</rich:message>
</h:panelGroup>
Above if a radio option is not selected a required message is displayed. And when the user makes a selection I see the validation error disseapeares. Fair enough !
My problem is when the user navigates to next page and then by using back button of the browser comes back to this page again I can see my gender field is selected accordingly but validation error is still displayed.
Does anyone know if there is a workaround to clear the h:message field once I click the command button so validation error won't be displayed when I go back to the same page?
Not sure if this works. I have not tested it:
//idComponent is the Component whose message you want to clear, e.g. gender
void clearMessageForComponent (final String idComponent) {
if (idComponent != null) {
Iterator<FacesMessage> it = FacesContext.getCurrentInstance().getMessages(idComponent);
while(it.hasNext()){
((FacesMessage)it.next()).setDetail("");
}
}
}
It is important to understand that the browser back button won't trigger a request to the server.
that is not entirely correct, modern browsers do trigger a request if data was posted in previous stages of the navigation.
Clearing the Messages from the FacesContext won't fix your problem, since this will affect only the server side state of your application. Pushing the browser back button forces the clients browser to reload the page from the local browser cache.
It is important to understand that the browser back button won't trigger a request to the server.